我遇到了一个问题,该问题迫使我将一个漂亮的 oneliner 拆分为带有中间 let 的 {} 块.我根本不清楚这样做的原因.我能够在这个最小的例子中隔离问题:
I ran into an issue that forces me to split a nice oneliner into a {} block with an intermediate let. The reason for this isn't clear to me at all. I was able to isolate the issue in this minimal example:
struct AB { a: u8, b: u8, } impl AB { fn foo(&self) -> String { String::from("foo") } fn bar(self, x: String) -> String { format!("{} - {} - {}!", x, self.a, self.b) } } fn main() { let x = AB { a: 3, b: 5 }; let result = x.bar(x.foo()); println!("{}", result); }我的印象是 bar 函数的参数会在调用 bar 之前 被评估.foo 在执行过程中借用了 x,但是当它返回它的 String 时,借用就完成了,因为 String 是不是带有 x 生命周期的引用.当 bar 被调用时,foo 的借用应该结束.
I was under the impression that the arguments to the bar function would be evaluated before calling bar. foo borrows x during its execution, but when it returns its String, the borrow is finished, as String is not a reference bearing x's lifetime. When bar gets called, foo's borrow should be over.
然而,编译器不同意:
error[E0382]: borrow of moved value: `x` --> src/main.rs:17:24 | 17 | let result = x.bar(x.foo()); | - ^ value borrowed here after move | | | value moved here | = note: move occurs because `x` has type `AB`, which does not implement the `Copy` trait我并不反对 bar 确实移动 x 的事实.我的问题是 foo 借用 x after 移动发生的声明.
I'm not disagreeing with the fact that bar indeed moves x. My issue is with the statement that foo borrows x after the move takes place.
一个简单(但丑陋)的修复:
A simple (but ugly) fix:
struct AB { a: u8, b: u8, } impl AB { fn foo(&self) -> String { String::from("foo") } fn bar(self, x: String) -> String { format!("{} - {} - {}!", x, self.a, self.b) } } fn main() { let x = AB { a: 3, b: 5 }; let y = x.foo(); let result = x.bar(y); println!("{}", result); }将 x.foo() 的赋值分离到一个中间变量 y 编译得很好,证实了我的期望,借用确实结束了一次 foo 返回,但为什么这有效?我对评估顺序有什么不明白的地方吗?为什么我不能去掉中间的 let y ?
separating the assignment of x.foo() to an intermediate variable y compiles fine, confirming my expectation that the borrow is indeed over once foo returns, but why does this work? Is there something I don't understand about evaluation order? Why can't I get rid of the intermediate let y ?
推荐答案求值顺序,以借用为目的,从左到右.
Evaluation order, for the purpose of borrows, is from left to right.
这意味着 bar 调用的主题,x 的移出"提及,在 x 的借用"提及之前被考虑 在 foo 调用中,因此,编译器认为该变量已被移出.
This means that the subject of the bar call, the "move-out" mention of x, is considered before the "borrow" mention of x in the foo call, and therefore, the compiler considers the variable to have been moved from.
对于外部提及是可变借用的类似情况,RFC 2025 已被接受为解决方案,但尚未实施.不幸的是,这个 RFC 似乎没有涵盖您的情况,其中外部使用是一种移动.
For the similar case where the outer mention is a mutable borrow, RFC 2025 has been accepted as a solution, but hasn't been implemented yet. Unfortunately this RFC doesn't appear to cover your case, where the outer use is a move.
更多推荐
为什么在调用一个按值获取 self 的方法时会借用一个移动的值,该方法的参数也调用一个方法?
发布评论