#[derive(Debug)]
struct Node {
elem1: Vec<i32>,
elem2: Vec<i32>,
}
impl Node {
fn new() -> Self {
Node {
elem1: Vec::new(),
elem2: Vec::new(),
}
}
}
fn test1() {
let node1 = Node::new();
let elem1 = node1.elem1;
let elem2 = node1.elem2;
// node1.elem1 = vec![1,2,3];
println!("{:?}", elem1);
println!("{:?}", elem2);
}
fn test2() {
let node2 = Box::new(Node::new());
let elem1 = node2.elem1;
let elem2 = node2.elem2;
println!("{:?}", elem1);
println!("{:?}", elem2);
}
fn main() {
test1();
test2();
}
上面的代码中函数test2是编译不过的,rust编译器报了如下的错误:
30 | let elem1 = node2.elem1;
| ----- value moved here
31 | let elem2 = node2.elem2;
| ^^^^^ value used here after move
函数test1中将结构体Node中的一个成员move后,仍然可以访问它的第二个成员,但是在函数test2中,通过Box创建的Node节点后却不能像test1那样操作。 请各位高手帮忙看下这其中的具体差别和原因,多谢!
1
共 7 条评论, 1 页
评论区
写评论开启NLL之后,你的代码就可以编译了。
这个网址有一个解释: https://stackoverflow.com/questions/44081865/ownership-tracking-in-rust-difference-between-boxt-heap-and-t-stack#
大概意思是栈上struct中field的所有权可以由编译器来追踪,但是堆上的(即使用Box分配的)不行。
这是因为Node的Drop是编译器生成的。在把elem2移走之后,编译器会标记原来Node里的elem2为uninitialized状态,Drop的时候就不会调用elem2的析构函数。 如果你为Node手动实现Drop你就会发现你没法把elem2移出来了。
嗯 好像是这样的哈哈,期待有更深入研究的人来解答下这个问题
事实上rust似乎也没有将Box的内存作为一个整体释放,请看下面的测试代码:
该程序的输出是:
Node有两个field。在test3中,将elem2从Node中move走后,elem1还是被释放了。
不太确定原因。 但我个人猜测是因为通过Box创建的Node内存是在堆中开辟的,并且释放内存时也是把这个Box作为一个整体释放,所以这里整个Box已经转移到elem1上面了,之后再使用node2就违反规则了吧?