Rust 的移动语义涉及复制数据吗? [重复]

问题描述 投票:0回答:1

我对 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 即使在

move
期间实际上也会执行复制操作,例如在本例中复制结构?此行为是否会根据是否处于发布模式而有所不同?

rust move-semantics
1个回答
6
投票

“移动”在许多语言(不仅仅是 Rust)中是一个语义术语,指的是“所有权转移”,并且并不“必然”规定该转移的机制。 在 Rust 中,移动值会将数据复制到其他地方,但会使值的源不可用(除非该源稍后使用有效值重新初始化,或者被移动的类型实现了 Copy)。

如何
在 Rust 中实现这一点是通过从源值到目标的按位复制。 在更高的优化级别,可以删除此副本,但也可能不会。

请注意,复制仅扩展到直接包含在正在移动的值中的值。 例如,当移动 Vec 时,它会复制

Vec

的数据指针、长度和容量,但不复制

Vec
的实际元素,这些元素位于该指针后面。 这允许您以相同的成本移动
any
Vec - 移动巨大的
Vec
和空的 Vec 都需要复制完全相同数量的内容(3 个指针大小的值)。
在您的代码中,获取 
foo
bar
的地址可能会阻止优化器实际删除副本,因为它无法统一它们的内存位置。 这样做并为两个变量返回相同的地址将违反

as-if 规则

换句话说:

如果您尝试查看代码将如何编译,

不要更改该代码以检查代码内部的值

,否则您几乎肯定会以某种方式更改优化器的行为。 相反,请查看生成的机器代码。

© www.soinside.com 2019 - 2024. All rights reserved.