为什么我不能连续两次调用FnMut?

8
这里选取代码片段,下面的代码无法编译。
fn foobar<F>(mut f: F)
    where F: FnMut(i32) -> i32
{
    println!("{}", f(f(2))); 
    // error: cannot borrow `f` as mutable more than once at a time
}

fn main() {
    foobar(|x| x * 2);
}

但这确实

fn foobar<F>(mut f: F)
    where F: FnMut(i32) -> i32
{
    let tmp = f(2);
    println!("{}", f(tmp)); 
}
 
fn main() {
    foobar(|x| x * 2);
}

我不明白为什么第一个代码片段是非法的:它实际上和第二个代码片段是一样的,只是写得更加简洁。更具体地说,为什么必须对 f 进行两次可变借用来调用 f(f(2))?它可以简单地借用内部的 f 来计算 f(2) 的值,然后借用外部的 f 并将其应用于该值。

5
很确定这只是一个借用检查器没有正确覆盖的情况,有点类似于这个问答 - kmdreko
是的,我同意这并不像看起来那样直观,但是这里的借用检查器没有深入到足以意识到发生了什么。我认为结果更好。f(f(2)) 不太好看,将其中一个值添加到变量中可以提高可读性。但再次强调,这只是个人意见。 - Dominik
1个回答

17
更具体地说,为什么f(f(2)) 必须可变借用f两次?
这里的借用发生在表达式求值的顺序中,即使所涉及的表达式是微不足道的变量访问时,表达式求值也总是从左到右。要计算的表达式是:
- f(f(2)) 由两个子表达式组成:ff(2)。 1. 计算函数值,f(并且作为FnMut调用要进行可变借用)。 2. 计算参数 f(2)。 - 计算函数值,f;因为它已经被借用,会导致错误。 - 计算参数,2。 - 使用参数调用f的借用,这是f(2) 的结果。 3. 使用f(2) 的结果作为参数调用f的借用,这是f(f(2)) 的结果。
借用检查器可以准确地接受这种情况,但需要识别第一个借用“尚未使用”,这目前不是借用检查器中的功能。

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