将Vec<u8>转换为&[u16]

6

我有一个从文件中读取的Vec<u8>字节序列 - 这些字节是文本格式(可能是UTF-16或其他一些2个字节的奇怪格式),我想将其转换为UTF-8。

let title = Vec::from_iter(bytes.take(title_length));
// Some Vec<u8> to &[u16] magic
let title = String::from_utf16_lossy(title);

目前我使用的是相当糟糕的代码:

let title: &[u16] = unsafe { std::slice::from_raw_parts(title_data.as_ptr(), title_data.len()) };

虽然这应该可以工作,但我遇到了错误,可能是由于take()调用造成的:

error: mismatched types:
 expected `*const u16`,
    found `*const core::result::Result<u8, std::io::error::Error>`
(expected u16,
    found enum `core::result::Result`) [E0308]

我是否应该映射take迭代器或其他内容?


那本来是一个非常好的问题,只是看起来不完整而已。 ;) - E net4
很奇怪。保存时也出了问题。等一下:/ - J V
请提供您问题的MCVE。您的一行代码引用了title_data,但是它在任何地方都没有定义。最好提供能够在Rust Playground上重现错误的代码。 - Shepmaster
3个回答

8

使用安全代码

以防万一,您需要安全地进行操作。

let title = Vec::from_iter(bytes.take(title_length));
let title: Vec<u16> = title
    .chunks_exact(2)
    .into_iter()
    .map(|a| u16::from_ne_bytes([a[0], a[1]]))
    .collect();
let title = title.as_slice();
let title = String::from_utf16_lossy(title);

请注意,这将分配内存并执行额外的复制操作(而不像不安全的替代方案那样)。

1
最终我在迭代器上使用了unwrap映射,但我仍然困惑为什么迭代器需要由结果组成。
let title_data = Vec::from_iter(bytes.take(title_length).map(|x| x.unwrap()));
let title: &[u16] = unsafe {
    std::slice::from_raw_parts(title_data.as_ptr() as *const u16, title_data.len() / 2)
};
let title = String::from_utf16_lossy(title);

3
因为它是一个IO迭代器,而且IO操作可能会失败。你希望你的应用程序因为某些文件无法再被读取而崩溃吗? - llogiq

0

有两个错误。首先,您需要对Result(我假设是from_raw_parts(..)的结果)进行.unwrap()操作;其次,长度太大了,因为u16占用的空间是u8的两倍,所以您需要除以2。


很遗憾,我无法解开结果 - from_raw_parts 给了我一个包含结果的切片:错误:在当前范围内找不到类型为 '&[core::result::Result<u8, std::io::error::Error>]' 的 'unwrap' 方法 - J V
1
看,这就是为什么你应该写一个完整的例子。我只能猜测bytes返回Option<Result<u8, Error>> - llogiq
它不会返回任何东西。它返回 std::iter::Take - J V

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接