When do I need to make a closure variable mutable? [duplicate]

六月ゝ 毕业季﹏ 提交于 2021-01-04 07:02:14

问题


Why do I need to make this closure variable mutable? The closure isn't returning anything, therefore nothing is being stored in the closure variable. This closure is only capturing a value from the environment and incrementing it.

fn main() {
    let mut x = 1;
    let mut y = || x = x + 1;
    y();
    println!("{}", x);
}

回答1:


Essentially, this is a consequence of one of Rust's soundness rules – you can't modify anything through a shared reference to a mutable reference. All the references in your chain of references need to be mutable for this to be possible.

Let's translate the closure in your example into roughly equivalent code using a struct:

struct Closure<'a> {
    x: &'a mut i32,
}

impl Closure<'_> {
    fn call(&mut self) {
        *self.x += 1;
    }
}

The closure captures x by mutable reference – it has to to be able to modify it. When the closure is called, it receives self by mutable reference – it has to to be able to mutate x through the self pointer.

Now if you want to call this closure, you need to make it mutable as well:

let mut x = 1;
let mut y = Closure { x: &mut x };
y.call();

If you don't make y mutable, you can't pass a mutable reference to y to the call() method.

The reason for the soundness rule mentioned at the beginning is easy to see: If you could mutate through a shared reference to a mutable reference, it would be easy to write code with multiple players holding mutable references to the same memory location, which violates one of the fundamental rules about Rust references.




回答2:


You have the situation exactly backwards. Returning a value does not require storing anything in the closure. Capturing, on the other hand, does require storing something in the closure. In your case, y needs to store a reference to x. And since that reference is mutable, the closure needs to be mutable.

Here you can see the difference in size between a closure that returns something (but captures nothing) and a closure that captures, and a closure that captures even more things.

fn main() {
    let mut a = 1;
    let mut b = 1;
    let mut c = 1;

    let small = || {
        return 10;
    };

    let mut bigger = || {
        a = a + 1;
    };

    let mut biggest = || {
        b = b + 1;
        c = c + 1;
    };

    small();
    bigger();
    biggest();

    println!("{}, {}, {}",
        std::mem::size_of_val(&small),
        std::mem::size_of_val(&bigger),
        std::mem::size_of_val(&biggest)
    );
}

Output:

0, 8, 16

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=f48399e830f6a6e597338114ea30a409

And for completeness, here is a closure that captures a value, but doesn't mutate it. You can see that it doesn't need to be mutable.

fn main() {
    let x = 1;
    let y = || x;
    println!("{}, {}", y(), std::mem::size_of_val(&y));
}


来源:https://stackoverflow.com/questions/59270277/when-do-i-need-to-make-a-closure-variable-mutable

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!