为什么在调用一个方法时会借用一个移动的值,该方法使用也调用方法的参数来按值获取自我?

Why is there a borrow of a moved value when calling a method that takes self by value with an argument that also calls a method?

我 运行 遇到了一个问题,它迫使我将一个不错的 oneliner 分成一个 {} 块和一个中间 let 块。我根本不清楚原因。我能够在这个最小示例中找出问题所在:

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,但是当它 returns 其 String 时,借用完成,因为 String 不是参考方位 x的一生。当 bar 被调用时,foo 的借用应该结束。

然而,编译器不同意:

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 移动发生之后的声明。

一个简单(但丑陋)的修复:

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 returns,但为什么这个工作?关于评估顺序,我有什么不明白的吗?为什么我不能摆脱中间 let y ?

求值顺序,为了借用,从左到右。

这意味着 bar 调用的主题,"move-out" 提及 x,在 "borrow" 提及 x 之前被考虑foo 调用,因此,编译器认为该变量已从中移出。

对于外部提及是可变借用的类似情况,RFC 2025已被接受为解决方案,但尚未实施。不幸的是,这个 RFC 似乎没有涵盖你的情况,外部使用是一个移动。