我能否从单个字节(u8)创建一个可变切片 &mut [u8]?

11
有时候我想从std::io::Read中读取单个字节。如果我尝试这样做:

Sometimes I want to read a single byte from a std::io::Reader. If I try to do this:

结果为:

有时候我想要从std::io::Read中读取单个字节。如果我试图这样做:

use std::io::{self, Read};

fn main() {
    let mut byte: u8 = 0;
    io::stdin().read(&mut byte).unwrap();
    println!("byte: {}", byte);
}
我遇到了以下错误(很明显,因为byte不是一个切片):

我遇到了以下错误(很明显,因为byte不是一个切片):

error[E0308]: mismatched types
 --> src/main.rs:6:22
  |
6 |     io::stdin().read(&mut byte).unwrap();
  |                      ^^^^^^^^^ expected slice, found u8
  |
  = note: expected type `&mut [u8]`
             found type `&mut u8`

有没有办法把 byte 作为简单的 u8 并只取其中一部分,然后将其传递给 read()?让这段代码工作的明显方法是使用长度为1的数组:

use std::io::{self, Read};

fn main() {
    let mut byte: [u8; 1] = [0];
    io::stdin().read(&mut byte).unwrap();
    println!("byte: {}", byte[0]);
}

但是这在代码的其他部分中有点奇怪的感觉,使用单个的u8而不是我必须索引的[u8; 1]会更自然。

如果无法从简单的u8创建一个切片,那也没关系,但我不知道是否可能,希望能知道一下。

2个回答

18

Rust 1.28+

slice::from_mut已经恢复,并且稳定可靠!

use std::{
    io::{self, Read},
    slice,
};

fn main() {
    let mut byte = 0;
    let bytes_read = io::stdin().read(slice::from_mut(&mut byte)).unwrap();
    if bytes_read == 1 {
        println!("read byte: {:?}", byte);
    }
}

Rust 1.0+

但是在代码的其他部分使用这种方式有点奇怪,更自然的方式是使用单个u8而不是我必须索引的[u8; 1]

创建长度为1的数组是最自然的方法:

use std::io::{self, Read};

fn main() {
    let mut bytes = [0];
    let bytes_read = io::stdin().read(&mut bytes).unwrap();
    let valid_bytes = &bytes[..bytes_read];
    println!("read bytes: {:?}", valid_bytes);
}

然而,有可能从一个单值的引用中不安全地创建切片:

use std::io::{self, Read};
use std::slice;

fn mut_ref_slice<T>(x: &mut T) -> &mut [T] {
    // It's important to wrap this in its own function because this is
    // the only way to tell the borrow checker what the resulting slice
    // will refer to. Otherwise you might get mutable aliasing or a
    // dangling pointer which is what Rust is trying to avoid.
    unsafe { slice::from_raw_parts_mut(x, 1) }
}

fn main() {
    let mut byte = 0u8;
    let bytes_read = io::stdin().read(mut_ref_slice(&mut byte)).unwrap();
    if bytes_read != 0 {
        println!("byte: {}", byte);
    }
}

请记住,切片基本上包含两个部分:指向内存区域的指针和长度。对于长度为1的切片,您只需要将长度添加到可变引用中,就可以得到一个切片。
Rust的早期版本有ref_slicemut_ref_slice函数。它们已被删除,因为它们的实用性尚未被证明(这不是一个常见问题),但调用它们是安全的。这些函数已移动到ref_slice crate,因此如果您想继续使用它们,那是一个可能性。

5

回答你的实际问题:不,你不能这样做,几乎永远没有必要。即使你无法从可读取的对象中获取一个可迭代的对象,你也可以将byte[0]放入另一个变量中并使用它。

相反,你可以使用Bytes迭代器

let byte: u8 = io::stdin().bytes().next().unwrap();

虽然我喜欢这种更简单的方法让代码工作,但是它并没有回答我的实际问题。 - Cornstalks
@Cornstalks:回答你的实际问题,不能这样做,而且几乎从不需要这样做。即使无法从可读对象中获得可迭代对象,你也可以将 byte[0] 存入另一个变量并使用它。 - Ry-
很酷,谢谢!那是个很好的评论,如果您能将其编辑到您的答案中,那将很棒。就现在而言,我会接受这个答案,但是那个评论对我来说真的很有意义。谢谢! - Cornstalks

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