无法借用为不可变-String和len()

9
let mut result = String::with_capacity(1000);

result.push_str("things... ");
result.push_str("stuff... ");

result.truncate((result.len() - 4));

然而,这是一个编译错误。与借用检查器和可能的可变性有关。
error[E0502]: cannot borrow `result` as immutable because it is also borrowed as mutable
 --> <anon>:7:22
  |
7 |     result.truncate((result.len() - 4));
  |     ------           ^^^^^^           - mutable borrow ends here
  |     |                |
  |     |                immutable borrow occurs here
  |     mutable borrow occurs here

然而,如果我稍微修改一下,就可以这样做:

let newlen = result.len() - 4;
result.truncate(newlen);

为什么?有没有方法可以将其改写成一行代码?(注:这是在 Rust 1.0 上)

1个回答

10

这是 Rust 借用检查过程中的一个不幸缺陷。这主要是由于

result.truncate(result.len() - 2)

等同于

String::truncate(&mut result, result.len() - 2)

在这里,您可以看到由于参数按从左到右的顺序计算,result 实际上是在使用 result.len() 之前被可变地借用的。

我在 Rust 的问题跟踪器中发现了这个问题:#6268。该问题已经关闭,支持非词法借用 RFC 问题。似乎这只是其中一个需要更多时间来完成的东西,尽管在 1.0 发布之前的时间紧迫。 这篇文章也可能会引起一些兴趣(即使它已经过去将近两年)。


这有助于澄清。这更像是一种烦恼而不是什么大问题。所以错误与truncate需要可变性和len需要不可变性之间的冲突有关?看起来result.len()会在交给truncate之前完成其工作,这意味着这更多是编译器的怪癖而已?http://doc.rust-lang.org/std/string/struct.String.html#method.len - jocull
你几乎是正确的 - 问题在于truncate需要&mut self,这会禁止在同一作用域中进行任何后续借用。而且,是的,似乎result.len()在交给truncate()之前就已经完成了,但是,我的答案解释了为什么不是这样 - 实际上,在计算方法接收器之前,参数就已经计算出来了,因此&mut result&result所需的result.len()之前就在作用域内了。 - Vladimir Matveev
@jocull,如果你对此感兴趣的话,可以在我的更新中链接的问题中找到更多信息。 - Vladimir Matveev
非常棒的信息 - 非常感谢!现在将其归因于编译器的怪癖,这只是生活的一部分。 - jocull

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