我有一个 Vec<char>
,需要转换为 &str
或 String
,但我不确定最佳的方法是什么。我查找了许多资源,但每个答案都似乎有些过时。在这个问题中的回答似乎不适用于最新版本。
我正在使用2015-3-19的夜间版本。
使用基于迭代器的方法和.collect
应该可以正常工作,在更新语言更改后:
char_vector.iter().cloned().collect::<String>();
(我选择用.cloned()
替换.map(|c| *c)
,但两种写法都可以。)
如果您的向量可以被使用,您也可以使用into_iter
来避免clone
fn main() {
let char_vector = vec!['h', 'e', 'l', 'l', 'o'];
let str: String = char_vector.into_iter().collect();
println!("{}", str);
}
Vec
转化为 String
而不进行任何分配。但这需要相当多的不安全代码:#![feature(raw, unicode)]
use std::raw::Repr;
use std::slice::from_raw_parts_mut;
fn inplace_to_string(v: Vec<char>) -> String {
unsafe {
let mut i = 0;
{
let ch_v = &v[..];
let r = ch_v.repr();
let p: &mut [u8] = from_raw_parts_mut(r.data as *mut u8, r.len*4);
for ch in ch_v {
i += ch.encode_utf8(&mut p[i..i+4]).unwrap();
}
}
let p = v.as_ptr();
let cap = v.capacity()*4;
std::mem::forget(v);
let v = Vec::from_raw_parts(p as *mut u8, i, cap);
String::from_utf8_unchecked(v)
}
}
fn main() {
let char_vector = vec!['h', 'ä', 'l', 'l', 'ö'];
let str: String = char_vector.iter().cloned().collect();
let str2 = inplace_to_string(char_vector);
println!("{}", str);
println!("{}", str2);
}
这将同时创建一个可变的u8
切片和一个char
切片,它们指向同一个缓冲区(破坏了Rust的所有保证)。请注意,u8
切片的大小是char
切片的四倍,因为char
始终占用4个字节。
let ch_v = &v[..];
let r = ch_v.repr();
let v: &mut [u8] = from_raw_parts_mut(r.data as *mut u8, r.len*4);
for ch in ch_v {
i += ch.encode_utf8(&mut v[i..i+4]).unwrap();
}
由于char
总是unicode,而我们的缓冲区始终恰好为4个字节(这是utf8编码的unicode字符所需的最大字节数),因此我们可以将字符编码为utf8而无需检查是否成功(它总是可行的)。encode_utf8
函数返回utf8表示的长度。我们的索引i
是最后一个写入的utf8字符的位置。
最后,我们需要做一些清理工作。我们的向量仍然是Vec<char>
类型。我们获取了所有所需的信息(指向堆分配数组的指针和容量)。
let p = v.as_ptr();
let cap = v.capacity()*4;
然后我们释放上一个向量所承担的所有义务,如释放内存等。
std::mem::forget(v);
最后,重新创建正确长度和容量的u8向量,并将其直接转换为字符串。不需要检查转换为字符串,因为我们已经知道utf8是正确的,因为原始的Vec<char>
只包含正确的Unicode字符。
let v = Vec::from_raw_parts(p as *mut u8, i, cap);
String::from_utf8_unchecked(v)
unsafe
;-) 修复应该很容易,参见Vec::from_raw_parts
的文档。 - user395760encode_utf8
作用于char
,这些字符始终是有效的Unicode:错误在于输入缓冲区太短(例如,尝试将4字节代码点写入 &mut v[i..i + 2]
)。 - huon
char
,这是非常便宜的(它将被编译成指针解引用,从内存中获取char
到(4字节)寄存器)。当然,避免克隆对于性能通常很重要,但char
并不是这样一种类型,放弃对Vec
的控制可能是不可取的。 - huon