rust - 涉及向量时移动闭包关键字

标签 rust

有人告诉我,当在闭包中使用 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/

相关文章:

rust - 使用no_std进行的 cargo 测试失败,错误代码为176、160

split - 在 Rust 中将拆分解包为元组?

overloading - 如何估算方法重载?

rust - 如何在Rust中的定位索引处获取位值?

rust - 如何在 future 链中使用包含在结果类型中的套接字?

即使文件存在,Rust 也找不到模块

mysql - 如何从一个 mysql::Conn 创建多个准备好的语句?

logging - 使用log4rs将每个主机变量附加到Rust中的所有日志消息

rust - 合并两个向量时匹配时为 "use of moved value"

pointers - 如何以字节为单位获取枚举成员的指针偏移量?