首页 文章

Rust如何移动不可复制的堆栈变量?

提问于
浏览
12

这里记录了Rust的移动语义的一个很好的例子:在Rust By Example网站上的Rust Move Semantics .

我对两个案例都有基本的了解 . 第一个原语是如何使用原语可以使用新的别名,原始文件仍可以使用,因为最终结果是 i32 使用 Copy 特征时看到的副本 . 这对我来说很有意义 .

此外,由于许多充分的理由,第二个示例在具有多个引用堆上的 i32 的别名方面是有意义的 . Rust强制执行所有权规则,因此现在无法使用原始别名创建新绑定 . 这有助于防止数据争用,双重释放等 .

但似乎还有第三个案例没有被谈到 . How does Rust implement moves of stack allocated structs that do not implement the Copy trait? 使用以下代码说明:

#[derive(Debug)]
struct Employee{
    age: i32,
}

fn do_something(m: Employee){
    println!("{:?}", m);
}

fn main() {
    let x = Employee {
        age: 25,
    };

    do_something(x);

    //compiler error below because x has moved
    do_something(x);
}

我知道:在上面的例子中, Rust will allocate the Employee on the stack . 上面的结构 does not implement the Copy trait 因此在分配给新别名时不会被复制 . 这对我来说非常混乱,因为如果在堆栈上分配了 Employee 结构,并且没有实现 Copy 特性在哪里/如何移动?它是否物理移动到 do_something() 的堆栈帧?

在解释这个难题时,我们对任何帮助表示赞赏 .

1 回答

  • 7

    它是否实际上被移动到do_something()的堆栈帧?

    是 . 非 Copy 类型的物理移动与 Copy 类型完全相同:带有 memcpy . 您已经了解原始 Copy -types会逐字节地复制到新位置(例如新的堆栈帧) .

    现在考虑 Box 的这个实现:

    struct Box<T> {
        ptr: *const T,
    }
    

    当你有

    let b = Box::new(27i32);
    do_something(b);    // `b` is moved into `do_something`
    

    然后在堆上分配 i32Box 将原始指针保存到该堆分配的内存 . 请注意, Box 直接(内部的原始指针)直接在堆栈上,而不是在堆上!只是 i32 在堆上 .

    当_1274152被移动时,正如我刚才所说的那样 . 这意味着堆栈内容被复制(!!)...因此只需逐个字节地复制指针 . 没有 i32 的第二个版本!

    在物理移动方面, Copy 和非 Copy 类型之间没有区别 . 唯一的区别是编译器对这些类型强制执行不同的规则 .

相关问题