【发布时间】:2021-08-28 10:31:48
【问题描述】:
这是我的问题:
fn main() {
let mut s = String::from("hello");
let s1 = &mut s;
let s2 = s1;
*s2 = String::from("world1");
*s1 = String::from("world2");
println!("{:?}", s);
}
这将导致编译错误,因为 s1 的类型 &mut String 没有实现 Copy 特征。
但是如果我将代码更改如下:
fn c(s: &mut String) -> &mut String {
s
}
fn main() {
let mut s = String::from("hello");
let s1 = &mut s;
let s2 = c(s1);
*s2 = String::from("world1");
*s1 = String::from("world2");
println!("{:?}", s);
}
它将编译没有任何错误消息。
我知道当一个引用传递给一个函数时,它意味着引用 borrows 是值而不是拥有它。
但在上述情况下,似乎当 s1 被传递给 fn c 并立即返回时, s2 borrowed s1 所以无法取消引用 s1直到 s2 超出它的生命周期。
那么当 s1 被传入 fn c 时发生了什么?
【问题讨论】:
-
您可以使用
let s2 = &mut *s1;而不是let s2 =c(s1);:引用不是Copy,但您可以像在函数中那样获取新的引用。请注意,这不是答案:我对导致c中的取消引用的规则不够清楚。 -
它看起来你有两个对同一个字符串的可变引用,但是如果你在
*s1 = String::from("world2");之后添加println!("{:?}", s2);,你会得到cannot assign to *s1 because it is borrowed。所以我猜这是由 NLL 引起的。不过这个问题很有趣。 -
PS:如果你在没有
fn c的情况下重新借用 s1 也会发生同样的情况:let s2 = &mut *s1;所以我想,在fn c()的情况下,rustc 正在执行一个隐蔽的重新借用,而在s2 = s1如果它只是在做一个move。相关问题:stackoverflow.com/questions/43036156/… -
这绝对是许多 Rust 新手的绊脚石。幸运的是,我认为 Sven 对副本的回答很好地解释了为什么会出现这种情况。
-
从那个答案来看,使函数编译的另一种方法是明确地给
s2一个引用类型:let s2: &mut _ = s1;可以正常工作,因为编译器会在已知目的地的任何时候推断重新借用成为可变引用。