代码之家  ›  专栏  ›  技术社区  ›  Archsx

理解Rust-Move语义:所有权转移是否涉及数据复制?

  •  0
  • Archsx  · 技术社区  · 1 年前

    作为Rust的初学者,我突然对 move Rust中的语义以及所有权转移时是否复制数据。

    #[derive(Debug)]
    struct Foo {
        name: i32,
        age: i32,
    }
    
    fn main() {
        let foo = Foo { name: 111, age: 1 };
    
        let ptr_foo = std::ptr::addr_of!(foo);
        println!("Address of foo: {:p}", ptr_foo);
    
        let bar = foo;
    
        let ptr_bar = std::ptr::addr_of!(bar);
        println!("Address of bar: {:p}", ptr_bar);
    }
    

    我最初认为“有一个变量foo,在移动后,我们简单地将其重命名为bar”,从而避免了复制其相应数据的需要。

    为了进一步研究,我使用了VSCode中的调试功能和一个名为“Hex Editor”的插件,发现两者 foo bar (内存地址 0x7fffffffd7d8 0x7fffffffd828 ),包含相同的数据( 6F 00 00 00 01 00 00 00 ).

    enter image description here

    这是否表明Rust实际上执行了复制操作,即使在 移动 ,例如在这种情况下复制结构?这种行为是否会因是否处于发布模式而有所不同?

    1 回复  |  直到 1 年前
        1
  •  4
  •   cdhowie    1 年前

    在许多语言中(不仅仅是Rust),“Move”是一个语义术语,指的是 所有权转让 而不是 必要地 规定一种转移机制。在Rust中,移动值会将数据复制到其他地方,但会使值的源不可用(除非该源后来用有效值重新初始化)。

    怎样 这是通过Rust从源值到目标值的逐位复制来实现的。在更高的优化级别上,可以消除此副本,但可能不会。

    请注意,副本仅扩展到直接包含在要移动的值中的值。例如,当移动 Vec 这将复制的数据指针、长度和容量 Vec 但是 的实际元素 Vec ,位于该指针后面。这允许您移动 任何 Vec 以同样的代价——移动一个巨大的 Vec 和一个空的 Vec 两者都需要复制完全相同数量的内容(3个指针大小的值)。

    在您的代码中,取的地址 foo bar 可能会阻止优化器实际删除副本,因为它无法统一它们的内存位置。这样做并为两个变量返回相同的地址将违反 as-if rule .

    换句话说:

    如果您正在尝试查看代码将如何编译, 不要更改该代码以从代码内部检查值 或者您几乎肯定会以某种方式更改优化器的行为。相反,请查看生成的机器代码。