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文档之后,我认为它遵循通用变量绑定的移动语义.在这种情况下,“数据”的所有权只能转移一次.虽然改变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 trait,这意味着如果您尝试将相同值的所有权传递给多个目标,则会自动调用clone.
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)); }
如果我们在将它传递给thread :: spawn之后再次尝试访问数据,我们将得到一个编译错误,如错误:使用移动值:’data’.这就是move关键字的作用.由于数据已移至闭包,因此该闭包现在负责释放其内存.值得注意的是,如果没有move关键字,此代码将无法编译,因为在这种情况下,数据将在main函数的末尾解除分配,但该线程可能比main函数更长.