为什么存储返回值可以避免两次借用

bin*_*y01 2 rust

use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
fn main() {
    let f = File::open("test.txt").expect("Can't open");
    let mut b = BufReader::new(f);
    let v = b.fill_buf().unwrap();
    println!("v: {:?}", v);

    b.consume(v.len());
}
Run Code Online (Sandbox Code Playgroud)

无法编译,错误是

error[E0499]: cannot borrow `b` as mutable more than once at a time
  --> src/main.rs:10:5
   |
7  |     let v = b.fill_buf().unwrap();
   |             ------------ first mutable borrow occurs here
...
10 |     b.consume(v.len());
   |     ^^^^^^^^^^-------^
   |     |         |
   |     |         first borrow later used here
   |     second mutable borrow occurs here
Run Code Online (Sandbox Code Playgroud)

将最后一行更改为:

let len = v.len();
b.consume(len);
Run Code Online (Sandbox Code Playgroud)

一切都很好。

我无法理解为什么第一个示例借用了两次东西,以及为什么将长度存储在变量中并将该变量传递给b.consume()可以 - 有人可以解释为什么 2. 变体可以,而第一个则不行?

Pit*_*taJ 6

当您遇到此类问题时,稍微简化一下事情会有所帮助。您可能知道,方法语法是关联函数调用的语法糖:

b.consume(v.len());
// desugars to
BufRead::consume(&mut b, [_]::len(v));
Run Code Online (Sandbox Code Playgroud)

参数表达式通常是从左到右计算的,因此我们在b释放 中持有的引用之前尝试获取一个新的可变引用v。在某些情况下,编译器可以识别并自动避免此问题,但这似乎不是其中之一。

你可能会问“为什么它说第二个可变引用?v是一个不可变引用!” 那么,当您调用 时, in 引用的生命周期v与可变引用的生命周期相关联b.fill_buf()。因此编译器认为可变引用b必须保持有效直到v被释放。

该修复有效的原因是它翻转了参数的顺序,v.len()首先评估,然后释放第一个引用。