有人告诉我,当在闭包中使用 move
关键字时,闭包会获得其环境中变量副本的所有权。但是这段代码不会编译:
use std::thread;
use std::time::Duration;
fn main() {
let mut data = vec![1, 2, 3];
for i in 0..3 {
thread::spawn(move || {
data[i] += 1;
});
}
thread::sleep(Duration::from_millis(50));
}
错误信息是
8:17 error: capture of moved value: `data`
data[i] += 1;
^~~~
一些解释
Rust knows this wouldn't be safe! If we had a reference to data in each thread, and the thread takes ownership of the reference, we'd have three owners!
是否意味着副本只复制栈上的元数据而不是堆上的真实数据?也就是说,引用被复制是因为数据类型本身就是引用类型,而不是引用&mut
语法创建的引用。 move
关键字在堆栈上复制数据是否适用于所有数据类型?因此,当谈到像 i32
这样的类型时,它按值进行复制,如果它是像 vector 这样的类型,则按引用进行复制。
我的初衷是了解move
关键字的确切行为。在仔细查看 Rust 文档后,我认为它遵循一般变量绑定(bind)的移动语义。在这种情况下,“数据”的所有权只能转移一次。尽管将 0..3
更改为 0..1
并没有什么不同。此外,确实复制了堆栈上的元数据,而不是堆数据。
最佳答案
Does it mean that the copy only copies the metadata on the stack not the real data on the heap? In other words, the reference is copied because the data type itself is a reference type by nature, not referring to the reference created by &mut syntax. Is it true for all data types that the move keyword copies data on the stack? So when it comes to type like i32 it copies by value, and by reference if it is type like vector.
当变量的所有权转移时,不会执行深拷贝。所有的指针仍然指向相同的值,堆内存没有被触及。所有权转让是一项设计成本低廉的操作。如果您需要深拷贝,您可以在 Vec
上显式调用 clone
方法。克隆成本低廉的某些类型(例如 i32
)实现了 Copy
特性,这意味着如果您尝试传递所有权,将自动调用 clone
到多个目的地的相同值(value)。
My original intention is to understand the exact behavior of the move keyword. After a closer look at the Rust docs, I think it follows move semantics of general variable bindings. In this case, the ownership of "data" can only be transferred once. Though change 0..3 to 0..1 doesn't make a difference. Also it's true that the metadata on the stack is copied, not the heap data.
使用 0..1
不起作用,因为编译器不会检查可迭代范围 0..1
是否仅包含单个元素。所以使用 0..1
不编译,但是完全删除 for
循环在逻辑上是等价的并且编译
use std::thread;
use std::time::Duration;
fn main() {
let mut data = vec![1, 2, 3];
thread::spawn(move || {
data[0] += 1;
});
thread::sleep(Duration::from_millis(50));
}
如果我们在将 data
传递给 thread::spawn
后再次尝试访问它,我们将得到一个编译错误,如 error: use of moved value : '数据'
。这就是 move
关键字所做的。由于 data
已移至闭包,该闭包现在负责释放其内存。还值得注意的是,如果没有 move
关键字,这段代码将无法编译,因为在那种情况下,data
将在 main
的末尾被释放函数,但线程可能比 main
函数存活时间更长。
关于rust - 涉及向量时移动闭包关键字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37107059/