String 从Vec创建字符串<;char>;
我有一个String 从Vec创建字符串<;char>;,string,rust,String,Rust,我有一个Vec,我需要把它变成&str或字符串,但我不确定最好的方法。我环顾四周,发现的每一种资源似乎都在某种程度上过时了。中的答案似乎不适用于最新版本 我使用的是2015-3-19《夜间》杂志,基于迭代器的方法与一起使用。在更新语言更改后,collect应该可以工作: char_vector.iter().cloned().collect::<String>(); char_vector.iter().cloned().collect::(); (我选择用.clone()替换.
Vec
,我需要把它变成&str
或字符串,但我不确定最好的方法。我环顾四周,发现的每一种资源似乎都在某种程度上过时了。中的答案似乎不适用于最新版本
我使用的是2015-3-19《夜间》杂志,基于迭代器的方法与一起使用。在更新语言更改后,collect
应该可以工作:
char_vector.iter().cloned().collect::<String>();
char_vector.iter().cloned().collect::();
(我选择用.clone()
替换.map(|c |*c)
,但两者都有效。)如果你的向量可以被消耗,你也可以使用进入iter
以避免克隆
fn main() {
let char_vector = vec!['h', 'e', 'l', 'l', 'o'];
let str: String = char_vector.into_iter().collect();
println!("{}", str);
}
您可以将Vec
转换为字符串
,而无需进行任何分配。但它需要一些不安全的代码:
#![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);
}
我们需要它来迭代unicode字符,并用utf8编码的对应字符替换它们。由于utf8总是较短或与unicode长度相同,因此我们可以保证不会覆盖尚未阅读的任何部分
for ch in ch_v {
i += ch.encode_utf8(&mut v[i..i+4]).unwrap();
}
由于char
始终是unicode,我们的缓冲区始终正好是4个字节(这是utf8编码的unicode字符所需的最大字节数),因此我们可以将字符编码为utf8,而无需检查它是否工作(它将始终工作)。encode\u utf8
函数返回utf8表示的长度。我们的索引i
是最后写入的utf8字符的位置
最后,我们需要做一些清理。我们的向量仍然是Vec
类型。我们获得了所需的所有信息(指向堆分配数组和容量的指针)
然后我们从所有义务中释放前一个向量,比如释放内存
std::mem::forget(v);
最后以正确的长度和容量重新创建u8向量,并直接将其转换为字符串。不需要检查到字符串的转换,因为我们已经知道utf8是正确的,因为原始的Vec
只能包含正确的unicode字符
let v = Vec::from_raw_parts(p as *mut u8, i, cap);
String::from_utf8_unchecked(v)
在这种情况下,克隆是一个char
,这是非常便宜的(它将编译成一个指针解引用,将char从内存带到一个(4字节)寄存器)。当然,避免克隆通常对性能很重要,但是char
不是这样的类型,放弃对Vec
的控制可能并不可取。对于超便宜的部分,我不知道。只是想为克隆提供替代方案,这在其他不太便宜的情况下也会有所帮助哦,对了,我误读了构造函数(它将容量乘以元素大小,但只将其用于分配大小,而不用于容量)。好吧,现在我们有一个很有启发性的例子,说明为什么不应该轻率地使用不安全的。-)不过修复应该很容易,请参阅Vec::from_raw_parts
.niat trick的文档。“由于我们的字符绝对是unicode,我们可以将它们编码为utf8而不检查它是否有效”:fwiw,encode\u utf8
对char
s进行操作,这些字符始终是有效的unicode:错误在于输入缓冲区太短(例如,试图将一个4字节的代码点写入&mut v[i..i+2]
)。谢谢,补充了这一信息
std::mem::forget(v);
let v = Vec::from_raw_parts(p as *mut u8, i, cap);
String::from_utf8_unchecked(v)