我遇到了一些 Rust 代码的问题,在某些情况下我被允许多次借用可变的东西(第一个令人困惑的部分),但其他情况下则不行。
我写了下面的例子来说明: ( Playground )
struct NoLifetime {}
struct WithLifetime <'a> {
pub field: &'a i32
}
fn main() {
let mut some_val = NoLifetime {};
borrow_mut_function(&mut some_val);
borrow_mut_function(&mut some_val); // Borrowing as mutable for the second time.
let num = 5;
let mut life_val = WithLifetime { field: &num };
borrow_lifetime(&mut life_val);
borrow_lifetime(&mut life_val); // Borrowing as mutable for the second time.
let num_again = borrow_lifetime(&mut life_val); // Borrow, assign lifetime result
borrow_lifetime(&mut life_val); // Compiler: cannot borrow `life_val` as mutable more than once
}
fn borrow_mut_function(val_in: &mut NoLifetime) -> String {
"abc".to_string()
}
fn borrow_lifetime<'a>(val_in: &'a mut WithLifetime) -> &'a i32 {
val_in.field
}
如果你看到了,我可以多次借用 some_val
和 life_val
作为可变的。但是,给borrow_lifetime
的返回值赋值后,我就不能再借了。
我的问题如下:
- 来自 Rust Book 中关于借款的“规则” ,我应该在范围内对相同的值有“恰好一个可变引用”。但是,在上面的代码中,每次调用
borrow_
函数时,我都将借用为可变的。 - 为什么当我有一个函数返回与参数具有相同生命周期的东西时不允许相同类型的借用,并且我分配了那个参数。
如有任何帮助,我们将不胜感激。我想这里发生的事情是我误解了“借用为可变”的真正含义,以及何时确定某些东西被借用为可变。
最佳答案
Chris already gave the gist of it ,但我认为值得进一步解释。
在 Rust 中有2转移所有权的方法:
- 移动是永久转移
- 借用是临时转让,所有权有望归还
与许多其他语言一样,Rust 使用一堆词法作用域 对时间流逝进行建模。因此,目前,借用从创建它的地方开始,一直延伸到其作用域的末尾。
因此,借用何时结束的问题类似于询问借用是在什么范围内创建的。
让我们用带编号的行回顾一下您的示例:
fn main() {
let mut some_val = NoLifetime {}; // 1
borrow_mut_function(&mut some_val); // 2
borrow_mut_function(&mut some_val); // 3
//
let num = 5; // 4
let mut life_val = WithLifetime { field: &num }; // 5
borrow_lifetime(&mut life_val); // 6
borrow_lifetime(&mut life_val); // 7
//
let num_again = borrow_lifetime(&mut life_val); // 8
borrow_lifetime(&mut life_val); // 9
}
调用函数时,借用参数:
- 至少在函数调用期间
- 直到结果被丢弃的那一刻,如果结果与参数共享生命周期
那么,让我们看看这个:
在第 (2) 和 (3) 行调用
borrow_mut_function
返回一个String
:结果不与参数共享任何生命周期,因此参数仅在函数调用的生命周期内借用。在第 (6) 和 (7) 行调用
borrow_lifetime
返回&'a i32
:结果与参数共享生命周期,因此参数被借用到结果范围的末尾...这是因为结果未被使用而立即结束。在第 (8) 行调用
borrow_lifetime
,它返回一个&'a i32
并将结果分配给num_again
:结果与参数共享一个生命周期,因此参数被借用到num_again
范围结束。在第 (9) 行你调用了
borrow_lifetime
但是它的参数仍然被num_again
借用所以这个调用是非法的。
就是这样,这就是 Rust 今天的工作方式。
以后有电话non-lexical borrows .也就是说,编译器会意识到:
num_again
从未使用过num_again
没有特定的析构函数(没有Drop
实现)
因此可以决定它的借用结束早于词法范围的结束。
关于Rust 借用检查器仅在返回具有相同生命周期的引用的函数时多次提示借用是可变的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38006421/