为什么允许我在嵌套函数 (Rust) 中有多个 &mut 引用?

Why am I allowed to have multiple &mut refs in nested functions (Rust)?

提问人:rico5678 提问时间:12/13/2021 更新时间:12/13/2021 访问量:905

问:

我是 rust 的新手,我想知道为什么以下代码不会导致:不能一次多次借用 val 作为可变错误。似乎当我到达函数时,我应该对同一个原始变量有三个单独的引用:second_layerval

val_ref在主功能体中

val_ref2在first_layer函数体中

val_ref3在second_layer函数体中

任何帮助将不胜感激!

fn first_layer(val_ref2: &mut String)
{
    *val_ref2 = String::from("first_layer");
    println!("{}", val_ref2);
    second_layer(val_ref2);
}

fn second_layer(val_ref3: &mut String)
{
    *val_ref3 = String::from("second_layer");
    println!("{}", val_ref3);

}

fn main()
{
    let mut val = String::from("asdf");
    let val_ref: &mut String = &mut val;

    first_layer(val_ref);

    println!("{}", val_ref);

}

谢谢

参考 不变性 可变 借用检查器

评论

3赞 Joe_Jingyu 12/13/2021
这是由于隐式再借。请看一下这篇文章
2赞 user4815162342 12/13/2021
@Joe_Jingyu 允许嵌套引用存在的不是重新借用,而是相反 - 是嵌套引用允许重新借用(显式隐式)。这个问题似乎在问为什么一开始就允许嵌套引用的别名,而链接的答案并没有解决这个问题。
1赞 Joe_Jingyu 12/13/2021
感谢您的评论,@user4815162342。我不清楚为什么你认为链接的帖子没有解决这个案子。难道不是因为 reborrow 没有被移动,在调用 in 后仍然可以访问吗?val-reffirst_layermain
1赞 user4815162342 12/13/2021
@Joe_Jingyu 因为这里的提问者问的是,嵌套引用是如何开始的,而不管隐式重借如何。换言之,当 compile 明显创建对 的别名可变引用时,为什么会编译?隐式再借的讨论没有涵盖这一点,因为它只是解释了隐式再借如何通过创建嵌套引用来防止引用被移动。它没有解释为什么允许嵌套的内部引用从外部引用对数据进行别名。let mut i = 0i32; let r1 = &mut i; let r2 = &mut *r1i
1赞 Joe_Jingyu 12/13/2021
@user4815162342我明白你的意思了。但是,我不知道 RFC#2094 是否是关于重新借用动机的良好文档。如果你知道一个更适合初学者。我也想读书。谢谢。

答:

0赞 hkBst 12/13/2021 #1

在函数调用期间,调用另一个函数的函数中的引用暂时不存在。

标识符不会自动存在于堆栈下部调用的函数中。仅仅因为一个函数调用另一个函数并不意味着被调用方应该有权访问调用方的局部变量。如果你尝试过,你会得到一个。not found in this scope

您可以(尝试)做的是创建一个闭包来捕获调用方的环境,然后重用调用方的变量之一。但是你会发现,如果你违反了借用规则,编译器就会抱怨。

fn first_layer(val_ref2: &mut String) {
    // println!("{}", val); // Cannot use val from main!
    *val_ref2 = String::from("first_layer");
    println!("{}", val_ref2);
    (|val_ref3: &mut String| {
        *val_ref3 = String::from("second_layer");
        println!("{}", val_ref3);
        println!("{}", val_ref2); // This is not allowed
    })(val_ref2);
}

fn main() {
    let mut val = String::from("asdf");
    let val_ref: &mut String = &mut val;

    first_layer(val_ref);

    println!("{}", val_ref);
}

另一种思考方式是内联。如果将函数内联到函数中,则会得到:second_layerfirst_layer

fn first_layer(val_ref2: &mut String)
{
    *val_ref2 = String::from("first_layer");
    println!("{}", val_ref2);
    *val_ref2 = String::from("second_layer");
    println!("{}", val_ref2);
}

这完全没问题!

因此,将最后两行抽象为自身函数的代码也应该完全没问题。

评论

0赞 user4815162342 12/14/2021
请注意,您还可以在同一函数中创建对相同数据的两个可变引用,例如 .let mut i = 0i32; let r1 = &mut i; let r2 = &mut *r1;
0赞 hkBst 12/14/2021
@user4815162342,如果您尝试使用它们,您将收到错误:fn main() { let mut i = 0; let r1 = &mut i; let r2 = &mut *r1; *r1 += 1; *r2 += 1; }
0赞 user4815162342 12/14/2021
如果使用 ,则不会收到错误,并且仅在删除后使用。但这并不能否定为什么 Rust 首先允许它们存在的问题。我认为原因是:1)允许重新借用,2)允许预测,即获得对你所引用的部分数据的可变引用。因此,嵌套引用是投影的一种特例。r2r1r2