为什么可变引用可以使用,但可变变量不能使用?

3

我有一个可变的字符串变量,还有一个不可变的变量,绑定到一个可变引用的不可变变量。

let mut string = String::from("test");
let variable: &mut String = &mut string;
variable.push_str(" test");
string.push_str(" test");

这个操作失败:

error[E0499]: cannot borrow `string` as mutable more than once at a time
 --> src/main.rs:5:5
  |
3 |     let variable: &mut String = &mut string;
  |                                      ------ first mutable borrow occurs here
4 |     variable.push_str(" test");
5 |     string.push_str(" test");
  |     ^^^^^^ second mutable borrow occurs here
6 | }
  | - first borrow ends here
  1. 为什么第二个变量不可变的情况下,我可以调用push_str方法?
  2. 为什么我可以在第二个变量上调用push_str方法而不能在第一个变量上调用?
2个回答

5

您会遇到这个错误,是因为可变借用是独占的:

let mut string = String::from("test")
let variable = &mut string;

在这里,您创建了一个可变引用,因为可变引用意味着独占访问,现在无法访问原始变量,否则会违反别名保证。

考虑以下情况:

let mut string = String::from("test");
{
    let variable = &mut string;
    variable.push_str(" test");
}
string.push_str(" test");

这个代码会成功编译并运行,因为可变引用在原始变量再次被访问之前就已经超出了作用域。
你可以在Rust书中查看更多信息(第二版的书籍可以查看此链接)。
至于为什么可以在非mut变量上调用突变方法,这是因为push_str()方法接受&mut作为其接收方;如果您已经拥有了&mut,则直接使用它,但如果没有,则Rust将自动尝试为您创建一个,如果变量不是mut,则这是不可能的:
let mut string = String::from("test");

string.push_str("test");
// equivalent to:
String::push_str(&mut string, "test");  // won't work if `string` is not `mut`

let variable = &mut string;
variable.push_str("test");
// [almost] equivalent to:
String::push_str(variable, "test");  // works because `variable` is already `&mut`

上面的例子中我用了“几乎”,因为在这种情况下还有另一步叫做“重新借用”,它基本上确保可变引用可以在此调用之后再次使用,而不是被移动到函数调用中,但对于这个答案并不重要。


我在不理解这本书的情况下来到这里,这个答案帮助我进一步解释了它。对我来说重要的部分是提到了String::push_str(&mut string...),因为这本书假定读者知道string.push_str是以那种方式实现的,而没有提到它。 - Peter

3
《Rust Book》很好地解释了问题1:

Rust Book

let mut x = 5;
let y = &mut x;

y is an immutable binding to a mutable reference, which means that you can’t bind 'y' to something else (y = &mut z), but y can be used to bind x to something else (*y = 5).

基本上,variable.push_str(" test"); 是改变了 variable 所引用的 String,但它并不影响 variable(即绑定)本身。


编译器错误应该会解答问题2。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接