[英]What does the equal '=' actually do in rust (with/without 'let')?
当 rust 执行 memcpy 并调用 drop 函数时,我感到很困惑。 我阅读了一些相关页面,但没有找到对此的详细描述。
下面是一些简单的代码:
struct MyType {
name: String,
age: i32
}
impl MyType {
fn new() -> Self {
let tmp = MyType {
name: String::from("Joy"),
age: 1
};
let addr = &tmp as *const MyType as usize;
println!("Calling new.");
println!("tmp : name: {}, age: {}", tmp.name, tmp.age);
println!("addr: 0x{:X}\n",addr);
tmp
}
}
impl Drop for MyType {
fn drop(&mut self) {
println!("Calling drop.\n");
}
}
fn main() {
println!("");
let a = MyType{
name: String::from("Tom"),
age : 10
};
let addr = &a as *const MyType as usize;
println!(" a : name: {}, age: {}", a.name, a.age);
println!("addr: 0x{:X}\n",addr);
let mut b = a;
let addr = &b as *const MyType as usize;
println!(" b : name: {}, age: {}", b.name, b.age);
println!("addr: 0x{:X}\n",addr);
b = MyType::new();
let addr = &b as *const MyType as usize;
println!(" b : name: {}, age: {}", b.name, b.age);
println!("addr: 0x{:X}\n",addr);
let c = MyType::new();
let addr = &c as *const MyType as usize;
println!(" c : name: {}, age: {}", c.name, c.age);
println!("addr: 0x{:X}\n",addr);
b = c;
let addr = &b as *const MyType as usize;
println!(" b : name: {}, age: {}", b.name, b.age);
println!("addr: 0x{:X}\n",addr);
}
并输出:
> Executing task: cargo run --package hello_world --bin hello_world <
Compiling hello_world v0.1.0 (/home/dji/proj_learn_rust/hello_world)
Finished dev [unoptimized + debuginfo] target(s) in 0.21s
Running `target/debug/hello_world`
a : name: Tom, age: 10
addr: 0x7FFDB8636AF0
b : name: Tom, age: 10
addr: 0x7FFDB8636BE0
Calling new.
tmp : name: Joy, age: 1
addr: 0x7FFDB8636CB8
Calling drop.
b : name: Joy, age: 1
addr: 0x7FFDB8636BE0
Calling new.
tmp : name: Joy, age: 1
addr: 0x7FFDB8636DB0
c : name: Joy, age: 1
addr: 0x7FFDB8636DB0
Calling drop.
b : name: Joy, age: 1
addr: 0x7FFDB8636BE0
Calling drop.
之后let mut b = a;
,好像a
和b
的地址不一样。 既然a
不再有效,为什么不直接将a
的memory传给b
呢? 似乎在使用let
关键字时进行了浅拷贝(如 C 中的 memcpy),而没有调用 drop function。
c
和tmp
的地址是一样的。 这时候,似乎执行了真正的move而不是memcpy,没有调用drop function。
但是为什么b = c;
调用 drop function 而let mut b = a;
并let c = MyType::new();
不要?
是let
避免掉线吗?
让我们从简短的回答开始: let
不是避免 drop 调用,它是用来引入新变量的。 =
没有let
是简单的变量赋值。
a
、 b
和c
中的每一个,编译器必须分配一个 memory 位置。 这就是a
和b
具有不同地址的原因。 let mut b = a
将值从 memory 位置a
移动到 memory 位置b
。 在那之后, a
就不能再使用了。c
和tmp
不是同一个 function 的一部分。 此外, c
和tmp
中只有一个可以随时在 scope 中,因此它们可以重复使用相同的 memory 位置。let mut b = a
中, b
还没有值。 因此,没有什么可drop
的。 但是,在b = MyType::new()
中, b
已经包含在let mut b = a
中分配给它的值。 然后删除该值。 您可以通过更改MyType
的Drop
实现来打印已删除值的名称来验证这一点。 同样, c
尚不包含let c = MyType::new()
中的值。 但是,在b = c
中, b
已经包含在b = MyType::new()
中分配给它的值,必须首先删除它。 有关更多解释,您可以查看 Rust 参考中的let 语句和赋值表达式。 Drop
trait的文档也可能很有趣。
a
和tmp
。 可能,如果您将使用可能更改的--release
标志进行编译,因为编译器可以内联 function 调用或执行许多其他优化。new
function,所以一切都发生在同一个堆栈帧中。 这就是为什么编译器可能只是重新分配变量而无需使用 memory 进行任何实际操作。b
已经拥有一个值(之前在b = MyType::new();
行上创建)。 所以这个值应该在从c
分配后删除。 换句话说,它删除的不是b
的值,而是实际上之前使用行b = MyType::new();
创建的。 .
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.