为什么仅在声明不在​​循环中时才发生这种不变性错误?

时间:2019-07-17 11:10:20

标签: rust

我试图用从文件中获取的一些数据填充缓冲区,然后从该缓冲区读取以对该数据进行处理。所有这些都在循环内迭代进行。

如果我这样做,它将完美编译:

use std::fs::File;
use std::io::{BufReader, IoSliceMut, Read};

fn do_something(buffer_0: &[u8; 8], buffer_1: &[u8; 2]) {
    // Do something
}

fn main() {
    let file = File::open("/path/to/file").expect("Error opening file");

    let mut reader = BufReader::new(file);
    let buffer_0 = &mut [0; 8];
    let buffer_1 = &mut [0; 2];

    loop {
        let buffer = &mut [IoSliceMut::new(buffer_0), IoSliceMut::new(buffer_1)];
        reader
            .read_vectored(buffer)
            .expect("Error reading from file");
        do_something(buffer_0, buffer_1);
    }
}

现在,如果我在循环外部声明buffer,如下所示:

use std::fs::File;
use std::io::{BufReader, IoSliceMut, Read};

fn do_something(buffer_0: &[u8; 8], buffer_1: &[u8; 2]) {
    // Do something
}

fn main() {
    let file = File::open("/path/to/file").expect("Error opening file");

    let mut reader = BufReader::new(file);
    let buffer_0 = &mut [0; 8];
    let buffer_1 = &mut [0; 2];

    let buffer = &mut [IoSliceMut::new(buffer_0), IoSliceMut::new(buffer_1)];

    loop {
        reader
            .read_vectored(buffer)
            .expect("Error reading from file");
        do_something(buffer_0, buffer_1);
    }
}

出现以下编译错误:

error[E0502]: cannot borrow `*buffer_0` as immutable because it is also borrowed as mutable
  --> src/main.rs:21:22
   |
15 |     let buffer = &mut [IoSliceMut::new(buffer_0), IoSliceMut::new(buffer_1)];
   |                                        -------- mutable borrow occurs here
...
19 |             .read_vectored(buffer)
   |                            ------ mutable borrow later used here
20 |             .expect("Error reading from file");
21 |         do_something(buffer_0, buffer_1);
   |                      ^^^^^^^^ immutable borrow occurs here

buffer_1当然也是这样。

我不明白为什么这段代码在循环内被认为是不安全的。另外,是否可以在不移动buffer声明的情况下使其安全?

非常感谢锈大师的智慧:)

1 个答案:

答案 0 :(得分:1)

在第一个示例中,buffer的每个实例仅持续循环一次。由于存在非词性生存期,因此编译器可以计算出在调用IoSliceMut之后,您不会重用read_vectored的那些实例,因此释放了它们持有的可变借项,并且代码进行了编译

在第二个示例中,您明确地说IoSliceMut的这两个实例应在整个循环中保留,并且应将它们用于对{{1 }}-因此,直到最后一次迭代,它们的可变借位才可能释放。