为什么Rust中不允许嵌套不可变借用?

为什么Rust中不允许嵌套不可变借用?,rust,borrow-checker,Rust,Borrow Checker,考虑到非词汇生存期是如何工作的,我不明白为什么编译器不允许以下内容: fn main() { let mut x = 10; let y = &mut x; let z = &x; // Immutable reference scope starts and ends here. println!("{}", y); } 我理解嵌套(我所说的“嵌套”是指范围在没有调用以前定义的引用的情况下开始和结束)可变引用可能会使以前定义

考虑到非词汇生存期是如何工作的,我不明白为什么编译器不允许以下内容:

fn main() {
    let mut x = 10;
    let y = &mut x;
    let z = &x; // Immutable reference scope starts and ends here.
    println!("{}", y);
}
我理解嵌套(我所说的“嵌套”是指范围在没有调用以前定义的引用的情况下开始和结束)可变引用可能会使以前定义的引用无效。然而,我不清楚为什么不可变引用不能嵌套

下面的一位评论者回应道:


因此,分析仍然是局部的。当可变借用尚未完成时,您不能创建对某事物的不可变引用。这是一个简单的规则,很容易检查

我回答了为什么这个答案让我不满意,因为rust编译器执行的检查比这个更高级

fn main() {
    let mut x = 10;
    let y = &mut x;
    println!("{}", x); // error: immutable borrow occurs here
    println!("{}", y);
}
对我来说,这可能是幼稚的,它表明了一种足够复杂的能力,足以识别我上面描述的特殊情况,因为编译器已经在跟踪借用事件

问题的进一步澄清:


如果不可变借阅的范围在可变借阅的范围内开始和结束,而没有任何额外的中间借阅,是否有一个具体的例子说明为什么这会被认为是不安全的?如果可以证明这是安全的,那么编译器为什么不允许这样做呢?

确定引用的使用位置不是Rust的工作,因为这会给类型系统带来太多的负担,使其无法使用。因此,Rust无法判断不可变引用是否被发送到了另一个线程,当您使用不可变引用从该线程中读取时,该线程当前正在写入该值。

我理解为什么通常不能组合可变引用。但这并不能解释这个特殊情况。是的,我知道。问题仍然是:为什么。因此分析仍然是局部的。当可变借用尚未完成时,您不能创建对某事物的不可变引用。这是一个简单的规则,很容易检查。很抱歉,你仍然没有说服我为什么这是一个根本性的问题。并不是说我不相信你,但你的理由相当于“它就是这样。”而且,如果我删除不可变引用并打印x,我会得到一个精确的错误,指示“此处发生不可变借用”。编译器似乎足够复杂,可以精确地选择借用发生的位置。我的特殊情况似乎没有更高级。这就是所有权规则的工作原理,如所述:“在任何给定的时间,您可以有一个可变引用或任意数量的不可变引用。”“Rust的工作不是找出引用的使用位置。”我不打算讨论编译器的职责从何处开始或结束,但从我所知,rust编译器正试图这样做。例如,编译器给出的错误准确地告诉我借阅发生的位置和使用借阅的位置。此外,非词法生命周期似乎恰恰与此相关,至少在某种程度上是如此。