我在一些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
的返回值后,我就不能再借了。
我的问题如下:
1.从Rust Book中关于借用的“规则”中,我应该在作用域中有“一个可变引用”,指向相同的值。然而,在上面的代码中,我在每次调用borrow_
函数时都借用了可变的。
1.当我有一个函数,它返回与参数相同的生存期,并且我给参数赋值时,为什么不允许相同类型的借用呢?
任何帮助将不胜感激。我想这里发生的事情是我误解了“借用为可变的”的真正含义,以及何时确定某个东西是作为可变的被借用的。
2条答案
按热度按时间rkkpypqq1#
由于non-lexical borrows,Rust现在接受了这段代码。
对于非词法借用,借用在变量的最后一次使用时结束(本质上),注意析构函数是一次使用,析构函数在作用域的末尾运行。
因此,当编译器意识到:
num_again
从不使用num_again
没有特定的析构函数(没有Drop
实现)它决定它的borrow在它开始的那一行结束,而不是在词法作用域的末尾,因此
life_val
可以自由地再次使用。Chris already gave the gist of it,但我认为值得进一步解释。
在Rust中有2种转移所有权的方法:
*搬家是永久调动
*借用为临时过户,预计归还所有权
像许多其他语言一样,Rust使用一个 * 词法范围 * 的堆栈来建模时间传递。因此,* 就目前而言 *,借用从创建它的地方开始,一直延伸到其范围的末尾。
因此,借用何时结束的问题过去类似于询问借用是在什么范围内创建的。
让我们用编号行来回顾一下您的示例:
当一个函数被调用时,参数被借用:
让我们看看这个:
borrow_mut_function
,它返回一个String
:结果不与参数共享任何生存期,因此参数仅在函数调用的生存期内被借用。borrow_lifetime
,它返回一个&'a i32
:结果与参数共享生存期,因此参数被借用,直到结果的作用域结束……这是立即的,因为结果没有被使用。borrow_lifetime
,它返回一个&'a i32
,你把结果 * 赋值 * 给num_again
:结果与参数共享生存期,因此该参数被借用,直到num_again
作用域结束。borrow_lifetime
,但是它的参数仍然被num_again
借用,所以调用是非法的。这就是Rust当时的工作方式。
f5emj3cl2#
这是关于借用的范围,以及您是否保持借用有效。在上面的大多数调用中,
some_val
在函数调用期间被借用,但在函数返回时被返回。在例外情况下:
在调用
borrow_lifetime
的过程中借用了life_val
,但由于返回值与参数('a
)具有相同的生命周期,因此借用的范围被扩展为包括num_again
的生命周期,即直到函数结束。再次借用life_val
是不安全的,因为num_again
仍然是对它的引用。