如何将不可变切片传递给接受&mut impl Read的函数?

3

我有一个类似这样的fn:

use std::io::Read;

fn read_something(file: &mut impl Read) {
    let _ = file.read(&mut [0; 8]);
}

当我像这样将一个Vec的切片传递给它:
fn main() {
    let vector = vec![1, 2, 3, 4];
    read_something(&mut &vector[..]);
}

它能够正常工作。但是当我先将切片保存到变量中时,它就无法编译:

fn main() {
    let vector = vec![1, 2, 3, 4];
    let slice = &vector[..];
    read_something(&mut slice);
}

编译器告诉我,我

无法作为可变引用借用。

Playground

这两种情况有什么不同? 为什么第一个示例可以工作,即使 vector 没有声明为可变的? 如何将 &[u8] 切片传递给那个接受 &mut impl Readfn

1个回答

2
我应该如何将一个 &[u8] 切片传递给一个接受 &mut impl Read 的函数?在保存切片的变量中添加 mut 即可。
let vector = vec![1, 2, 3, 4];
let mut slice = &vector[..];
read_something(&mut slice);

请注意,这使得切片可变,意味着它可以被修改以引用不同的数据(read_something()会使用它)。它并不赋予切片改变不可变向量的能力。
这两种情况有何不同?为什么第一个示例可以工作,即使向量也没有声明为可变?
在第一种情况下,向量是不可变的,但持有切片的未命名临时对象是可变的。您的第一个示例会被展开成类似以下的内容:
let vector = vec![1, 2, 3, 4]; // immutable Vec
let mut tmp = &vector[..]; // mutable slice referring to immutable Vec
read_something(&mut tmp);
// here `tmp` may be pointing to different content
// (e.g. a subset of the vector, or something static)

向量不需要可变的是因为Read::read()针对&[u8]的实现并不会尝试修改切片的内容,它仅会修改切片本身(概念上是一个<指针, 长度>元组)。这样做是因为Read被实现为&[u8],所以当<&[u8] as Read>::read()接收到&mut self时,它的完整类型是&mut &[u8] - 一种可变引用到某些不可变数据切片的方式。
对于&[u8]来说,Read::read()所做的是把接收到的切片替换为一个更小的切片,该切片包含尚未读取的部分。(这允许“相同”的切片最终通过read()耗尽所有数据。)由于您读取的8字节缓冲区比作为读取源的4字节切片要大,所以经过read_something()调用后,修改后的tmp切片将为空。 (playground)

谢谢,那个可行。我仍然不太明白为什么可以创建一个可变的向量切片,而它并没有被声明为可变的? - David
@David 我希望答案已经涵盖了这一点,但我会尝试提供一个概述。您可以将切片视为两个指针对 [first, last)<pointer, length> 的组合。正是这对组合是可变的,即允许更改其所指向的数据。这就是 &mut &[u8] 的含义 - 对某些不可变数据的可变引用。它不允许您更改向量的内容,那将是 &mut [u8]&mut &mut [u8] 等。 - user4815162342
啊,我现在明白了,谢谢。 - David

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