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

jv4diomz  于 2022-11-12  发布在  其他
关注(0)|答案(1)|浏览(123)
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());
}

将不会编译,错误为

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

将最后几行更改为:

let len = v.len();
b.consume(len);

一切都好。
我不明白为什么第一个例子借用了两次,为什么在变量中存储长度并将该变量传递给b.consume()是可以的--有人能解释一下为什么2. variant是可以的,而第一个不是?

scyqe7ek

scyqe7ek1#

当你遇到这类问题时,把事情简单化会有帮助。你可能知道,方法语法是关联函数调用的语法糖:

b.consume(v.len());
// desugars to
BufRead::consume(&mut b, [_]::len(v));

参数表达式通常是从左到右求值的,所以我们尝试在释放v中的引用之前,获取一个新的对b的可变引用。在某些情况下,编译器可以识别并自动避免这个问题,但这似乎不是其中之一。
你可能会问:“为什么它说第二个可变引用?v是一个不可变引用!”当你调用b.fill_buf()时,v中的引用的生存期与可变引用的生存期相关联。所以编译器认为对b的可变引用必须保持有效,直到v被释放。
这个修复之所以有效,是因为它翻转了参数的顺序,首先计算v.len(),然后释放第一个引用。

相关问题