Rust 为什么结构的地址与被删除的地址不同?

Rust why is the address of struct not the same address that is being dropped?

我有这个代码:

struct Example {
    x: i32,
    b: Option<Box<Example>>,
}

impl Example {
    fn get_self(&self) -> String {
        format!("{:p}", self)
    }
}

impl Drop for Example {
    fn drop(&mut self) {
        println!("Droppped: {} {:p}", self.x, self);
    }
}

fn take(t: Example) {
    println!("Taken ownership");
}

fn main() {
    let mut myE = Example {
        x: 1,
        b: Some(Box::new(Example { x: 2, b: None })),
    };
    println!(
        "Parent: {} Child: {}",
        myE.get_self(),
        match &myE.b {
            Some(x) => x.get_self(),
            None => String::from("Error"),
        }
    );
    take(myE);
    println!("End!");
}

这是输出

Parent: 0x7ffdc8031560 Child: 0x556b88bb5ba0
Taken ownership
Droppped: 1 0x7ffdc80314a8
Droppped: 2 0x556b88bb5ba0
End!

请注意子地址与一旦超出范围就被删除的地址相同,但一旦父超出范围,它就会因某种原因发生变化。这是什么原因?

我希望输出是这样的:

Parent: 0x7ffdc8031560 Child: 0x556b88bb5ba0
Taken ownership
Droppped: 1 0x7ffdc8031560
Droppped: 2 0x556b88bb5ba0
End!

其中打印的地址与删除的地址相同。

这是在行动。当您按值传递某些内容时,它可以在内存中逐字移动。通常,出于效率原因,编译器可能会选择不移动某些内容,但您应该始终假设任何移动值的操作 可以 物理移动它。

确切的行为可能会随着不同的 Rust 版本、调试与发布版本、内联提示、link-time 优化、目标操作系统或体系结构而改变,或者只是你添加了另一行代码改变了栈帧的最佳布局。在所有情况下,您可以做出的唯一假设是移动的值 可能 最终位于内存中的不同位置。

举一个更简单的例子,你甚至不需要将值移动到另一个函数中:

fn main() {
    let mut myE = Example {
        x: 1,
        b: Some(Box::new(Example { x: 2, b: None })),
    };
    println!("Parent: {} Child: {}", myE.get_self(), match &myE.b {
        Some(x) => x.get_self(),
        None => String::from("Error")
    });

    // move the value
    let moved = myE;

    println!("End!");
}

这仍然会移动内存中的数据(至少在我 运行 它时,在调试版本中)。

装箱值不同,因为它是在堆上分配的。 Box 实际上只是一个指针,只是移动了指针;它指向的数据保留在同一个地方。