结构体所有权

4
struct Haha {
    pub a: u32,
    pub b: Vec<u32>,
}

let example = Haha {
    a: 32,
    b: vec![1],
}; 
let new_a = example.a;
let new_b = example.b;

我理解的是:
  1. new_aexample.a 的一个拷贝,所以 example 仍然拥有 example.a
  2. new_b 现在拥有 example.b,因为 example.b 已经被移动了。
Rust 是否会因为具有 Copy 特性而隐式地复制 example.a 呢?由于 example.b 是一个 Vec,没有实现 Copy 特性,所以所有权被移动而不是被复制?

请查看此博客文章 https://medium.com/@bugaevc/understanding-rust-ownership-borrowing-lifetimes-ff9ee9f79a9c"幸运的是,Rust 有 Copy trait。实现它的类型(所有原始类型都实现了)在赋值时使用复制语义,而所有其他类型则使用移动语义。" - ccheneson
1个回答

6
您的理解是正确的。a被复制,而b被移动。您可以尝试访问这两个字段来确认这一点。
println!("{:?}", example.a);

这将打印 32example.a 仍然可访问,因为它是被复制而不是移动的。
println!("{:?}", example.b);

访问 example.b 无法编译,会出现错误消息:

error[E0382]: borrow of moved value: `example.b`
  --> src/main.rs:13:22
   |
12 |     let _new_b = example.b;
   |                  --------- value moved here
13 |     println!("{:?}", example.b);
   |                      ^^^^^^^^^ value borrowed here after move
   |
   = note: move occurs because `example.b` has type `std::vec::Vec<u32>`, which does not implement the `Copy` trait

这正好证实了你所说的,即example.b被移动是因为它没有实现Copy特质。


谢谢您的快速回复!那么对于像我这样的 Rust 新手(可能不知道 vec 没有实现 copy trait),我们是否必须依赖编译器来检查所有权,因为复制是隐式完成的? - pandawithcat
@LouisLee 你可以在 API文档 中看到一个类型是否是 Copy - Jesper
@LouisLee 如果一个变量的大小在编译时已知(例如i32),它可以存储在堆栈中,因此复制速度很快。如果一个变量的大小在编译时未知(例如向量),它将存储在堆中,并在堆中存储指向内存位置的指针。Rust不会在堆中复制内存,因为这样做会很慢且效率低下。您可以假设如果一个变量正在使用堆,则它不会实现复制特性。 - Bruno Robert
我还有一个问题。我认为结构体和枚举默认保存在堆栈中,除非某些字段必须分配在堆中。所以如果我这样做:struct haha{ pub a: i32, pub b: inner } struct inner{ pub c: u32 }虽然我没有为结构体inner派生copy或clone trait,但我期望结构体inner被堆栈分配,但编译器告诉我它不是。那么结构体是存储在堆中,除非它们派生了copy trait吗? - pandawithcat
@LouisLee 不,Rust不会自动决定某个东西是在堆栈上分配还是在堆上分配。默认情况下,它们在堆栈上分配。一些结构体(例如Vec)的实现方式是在堆上分配它们。只是将某些东西标记为“Copy”或不标记并不会改变它是在堆栈上分配还是在堆上分配的方式。 - Jesper

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接