4 ms·
I'm having a tough time trying to understand this snippet for i in 0..3 { thread::spawn(move || { data[i] += 1; }); } What
by djhworld 11y ago
I'm having a tough time trying to understand this snippet
for i in 0..3 {
thread::spawn(move || {
data[i] += 1;
});
}
What is the 'move' thing here before the ||
- domenp 11y agoA quick search turned up this: https://doc.rust-lang.org/book/closures.html#move-closures https://doc.rust-lang.org/book/closures.html#move-closures.
- djhworld 11y agoGreat thanks.
- singlow 11y agoA move closure takes copies of the environment, instead of mutating the parent environment. https://doc.rust-lang.org/book/closures.html#move-closures https://doc.rust-lang.org/book/closures.html#move-closures
- pdpi 11y agoIt's more accurate to say that it takes ownership of the captured environment. Whether that means copying the values or moving ownership depends on whether the values are of a type that implements Copy
- rdtsc 11y agoBut isn't it confusing that it is called "move" instead of "copy" if it takes copies?
- steveklabnik 11y agoMove and Copy are identical at the assembly level. The only difference is what you can do with the older binding. Semantically speaking, both cause a memcpy, though the optimizer may elide them. That said, you're right that saying "copy" is misleading, for this reason. But moves _are_ a kind of copy.
- barosl 11y agoSo, for those who may know JavaScript, you may have seen code like this: var closures = []; for (var i=0;i<5;i++) { closures.push(function() { console.log(i); }); } The code above will result in incorrect results: 5, 5, 5, 5, 5. Because you're capturing `i` as a reference. To avoid this, JS devs typically do this: closures.push((function(i) { return function() { console.log(i); }; })(i)); Or, if you can afford the ES6 support: for (let i=0;i<5;i++) { /* `let`-scoped `i`s are created individually at each iteration, so it is safe to capture them by references. */ } Rust supports this pattern by a built-in syntax. That's what `move` means. If you prepend the `move` keyword before the closure, the variables will be captured by values, not references.
- kentosi 11y agoThanks for the explanation, but how would the move keyword know that you're referring to the i variable? Ie - what is there were multiple variables (such as a for loop with j in there)? Wouldn't it have been a better approach to add some sort of demarkation, such as i* or i^ (or whatever) to indicate this? Just curious.
- Chilinot 11y agoIt moves everything you are referencing in the closure from the outer scope to the closure.
- Manishearth 11y agoA closure captures all variables from its environment that it is using (no more than that). They can be captured by reference (which is the default), or by-move (which is done with the `move` keyword). In case it is being captured by move, _all_ captured variables will be moved. If you wish to capture a specific variable by reference in a move closure, create a reference (`let y = &x`) outside of the closure and use the reference y instead of x inside.
- pmarreck 11y agoI agree that this seems ugly