【发布时间】:2015-05-30 20:26:42
【问题描述】:
我现在正在学习 Rust。我想检查一下我对 rust 所有权的理解。我对递归结构中的所有权和借用概念感到困惑。我在rustbyexample.com看到了这段代码
// Allow Cons and Nil to be referred to without namespacing
use List::{Cons, Nil};
// A linked list node, which can take on any of these two variants
enum List {
// Cons: Tuple struct that wraps an element and a pointer to the next node
Cons(u32, Box<List>),
// Nil: A node that signifies the end of the linked list
Nil,
}
// Methods can be attached to an enum
impl List {
// Create an empty list
fn new() -> List {
// `Nil` has type `List`
Nil
}
// Consume a list, and return the same list with a new element at its front
fn prepend(self, elem: u32) -> List {
// `Cons` also has type List
Cons(elem, Box::new(self))
}
// Return the length of the list
fn len(&self) -> u32 {
// `self` has to be matched, because the behavior of this method
// depends on the variant of `self`
// `self` has type `&List`, and `*self` has type `List`, matching on a
// concrete type `T` is preferred over a match on a reference `&T`
match *self {
// Can't take ownership of the tail, because `self` is borrowed;
// instead take a reference to the tail
Cons(_, ref tail) => 1 + tail.len(),
// Base Case: An empty list has zero length
Nil => 0
}
}
// Return representation of the list as a (heap allocated) string
fn stringify(&self) -> String {
match *self {
Cons(head, ref tail) => {
// `format!` is similar to `print!`, but returns a heap
// allocated string instead of printing to the console
format!("{}, {}", head, tail.stringify())
},
Nil => {
format!("Nil")
},
}
}
}
fn main() {
// Create an empty linked list
let mut list = List::new();
// Append some elements
list = list.prepend(1);
list = list.prepend(2);
list = list.prepend(3);
// Show the final state of the list
println!("linked list has length: {}", list.len());
println!("{}", list.stringify());
}
如何可视化这段代码的栈和堆?
据我所知,prepend 拥有列表的所有权,在堆中分配空间并将列表移动到堆中。当prepend 完成时,它将新创建的列表移动(授予所有权)到外部变量。
这个可视化是否正确?
First List::new 返回 Nil,因此堆栈将包含 Nil。
list.prepend(1) 执行后,Nil 将在地址 0x0000(假设)的堆中,堆栈将包含 Cons(1,0x0000)。
list.prepend(2) 执行后 Cons(1,0x0000) 将在地址 0x00002 的堆中(假设),堆栈将包含 Cons(2,0x0002)。
list.prepend(3) 执行后 Cons(2,0x0002) 将在地址 0x00004(假设)的堆中,堆栈将包含 Cons(3,0x0004)。
现在,谁拥有 Cons(1,0x0000) 的所有权? Cons(2,0x0002) 是否拥有 Cons(1,0x0000) 的所有权?堆中的变量是否允许拥有资源的所有权?
从这段代码中,我假设堆中的变量可能拥有资源的所有权,所以如果 Rust 释放该变量,它也会释放资源。这个对吗?
【问题讨论】:
标签: rust