【问题标题】:When should I add mut to closures?什么时候应该将 mut 添加到闭包中?
【发布时间】:2018-10-03 19:59:11
【问题描述】:
fn main() {
    let mut a = String::from("a");
    let closure = || {
        a.push_str("b");
    };

    closure();
}

这不会编译:

error[E0596]: cannot borrow immutable local variable `closure` as mutable
 --> src/main.rs:7:5
  |
3 |     let closure = || {
  |         ------- consider changing this to `mut closure`
...
7 |     closure();
  |     ^^^^^^^ cannot borrow mutably

如果我在闭包中返回a而不添加mut,则可以编译:

fn main() {
    let mut a = String::from("a");
    let closure = || {
        a.push_str("b");
        a
    };

    closure();
}

这让我很困惑。似乎当我调用closure() 时,closure 将被借用,如果其中的某些内容是可变的。为什么我回a时不借?

【问题讨论】:

    标签: rust


    【解决方案1】:

    Rust 中有 3 个函数特征:FnFnMutFnOnce。向后退:

    • FnOnce 只保证值可以被调用一次,
    • FnMut 只保证值是可变的就可以调用,
    • Fn 保证该值可以被多次调用,并且不可变。

    闭包将automatically implement 那些特征,取决于它捕获的内容以及它如何使用它。默认情况下,编译器会选择 least 限制性特征;所以支持Fn 胜过FnMutFnMut 胜过FnOnce

    在你的第二种情况下:

    let mut a = String::from("a");
    let closure = || {
        a.push_str("b");
        a
    };
    

    这个闭包需要能够返回a,这需要FnOnce。它将a 移动到捕获中。如果您尝试再次调用您的闭包,它将无法编译。如果你尝试访问a,也会编译失败。

    这就是为什么FnOnce 是“最后的手段”实现。

    另一方面,您的第一个案例:

    let mut a = String::from("a");
    let closure = || {
        a.push_str("b");
    };
    

    最多需要一个对a 的可变引用,因此捕获是通过可变引用发生的。因为它捕获了一个可变引用,所以闭包实现了FnMut,因此只有在它本身是可变的时候才能被调用。

    如果你删除mut,在a前面,编译器会提示你它需要可变地借用a

    编译器不要求closure 本身被声明为可变的,直到你尝试调用它;毕竟你可以通过值将它传递给一个函数而不调用它(你自己),在这种情况下mut 将是多余的。

    【讨论】:

    • 关于您的最新段落。接收传值函数的函数是否会在其签名中将闭包标记为mut
    • @PaulRazvanBerg:可能,但不需要。这是因为如果您拥有某物的所有权,您始终可以将其重新绑定到可变绑定。那是let a = ...; let mut a = a;
    • 哦,我明白了。感谢您的及时回复先生!
    猜你喜欢
    • 1970-01-01
    • 2020-11-02
    • 2017-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-23
    • 2021-07-13
    • 2020-10-20
    相关资源
    最近更新 更多