我正在进入Rust编程实现一个小程序,我在字符串转换中有点迷失。
在我的程序中,我有一个向量如下:
let mut name: Vec<winnt::WCHAR> = Vec::new();
WCHAR
与我的Windows计算机上的u16
相同。
我将Vec<u16>
移交给C函数(作为指针),用它填充数据。然后我需要将向量中包含的字符串转换为&str
。但是,无论我尝试什么,我都无法让这种转换工作。
我设法完成的唯一工作就是将其转换为WideString
:
widestr = unsafe { WideCString::from_ptr_str(name.as_ptr()) };
但这似乎是走向错误方向的一步。
在假设向量包含有效且以null结尾的字符串的情况下,将Vec<u16>
转换为&str
的最佳方法是什么。
答案 0 :(得分:11)
然后我需要将向量中包含的字符串转换为
&str
。但是,无论我尝试什么,我都无法让这种转换工作。
没有办法让这个&#34;免费&#34;转换。
&str
是使用UTF-8编码的Unicode字符串。这是一种面向字节的编码。如果你有UTF-16(或不同但是常见的UCS-2编码),那么就无法读取另一个。这相当于尝试将JPEG图像作为PDF读取。两个数据块都可能是一个字符串,但编码很重要。
第一个问题是&#34;你真的需要这样做吗?&#34;。很多时候,您可以从一个函数中获取数据并将其转换回另一个函数,从不查看它。如果你可以逃脱,那可能是最好的答案。
如果你做需要转换它,那么你必须处理可能发生的错误。任意16位整数数组可能不是有效的UTF-16或UCS-2。这些编码具有边缘情况,可以轻松生成无效字符串。空终止是另一个方面 - Unicode实际上允许嵌入的NUL字符,因此以null结尾的字符串不能包含所有可能的Unicode字符!
一旦确保编码有效 1 并找出输入向量中有多少条目构成字符串,那么你必须解码输入格式并重新编码为输出格式。这可能需要某种新的分配,因此您最有可能最终使用String
,然后可以在&str
可以使用的任何地方使用。
有一种内置方法可将UTF-16数据转换为字符串:String::from_utf16
。请注意,它返回Result
以允许这些错误情况。还有String::from_utf16_lossy
,它用Unicode替换字符替换无效的编码部分。
let name = [0x68, 0x65, 0x6c, 0x6c, 0x6f];
let a = String::from_utf16(&name);
let b = String::from_utf16_lossy(&name);
println!("{:?}", a);
println!("{:?}", b);
如果您从指向u16
或WCHAR
的指针开始,则需要先使用slice::from_raw_parts
转换为切片。如果您有一个以null结尾的字符串,则需要自己找到NUL
并适当地切片输入。
1:这实际上是一种使用类型的好方法; &str
保证为UTF-8编码,因此无需进一步检查。同样,WideCString
可能会在构建时执行一次检查,然后可以跳过以后使用的检查。
答案 1 :(得分:0)
这是我对这种情况的简单攻击。必须有一个bug;修复你自己的情况:
let mut v = vec![0u16; MAX_PATH as usize];
// imaginary win32 function
win32_function(v.as_mut_ptr());
let mut path = String::new();
for val in v.iter() {
let c: u8 = (*val & 0xFF) as u8;
if c == 0 {
break;
} else {
path.push(c as char);
}
}