Rust 谁拥有一个箱子?
我现在正在学习生锈。我想检查一下我对rust所有权的理解。我对递归结构中的所有权和借用概念感到困惑。我在中看到了这个代码Rust 谁拥有一个箱子?,rust,Rust,我现在正在学习生锈。我想检查一下我对rust所有权的理解。我对递归结构中的所有权和借用概念感到困惑。我在中看到了这个代码 //允许引用Cons和Nil而不使用名称空间 使用列表:{Cons,Nil}; //链表节点,可以采用这两种变体中的任何一种 枚举列表{ //缺点:包装元素和指向下一个节点的指针的元组结构 Cons(u32,盒子), //Nil:表示链接列表结束的节点 无 } //方法可以附加到枚举 impl列表{ //创建一个空列表 fn new()->List{ //`Nil`具有类型`
//允许引用Cons和Nil而不使用名称空间
使用列表:{Cons,Nil};
//链表节点,可以采用这两种变体中的任何一种
枚举列表{
//缺点:包装元素和指向下一个节点的指针的元组结构
Cons(u32,盒子),
//Nil:表示链接列表结束的节点
无
}
//方法可以附加到枚举
impl列表{
//创建一个空列表
fn new()->List{
//`Nil`具有类型`List`
无
}
//使用一个列表,并返回同一个列表,其前面有一个新元素
fn预结束(自身,元素:u32)->列表{
//`Cons`还有类型列表
Cons(元素,方框::新(自身))
}
//返回列表的长度
fn len(&self)->u32{
//必须匹配'self',因为此方法的行为
//取决于“self”的变体`
//`self`具有类型`&List`,`*self`具有类型` List`,在
//具体类型“T”优先于引用“&T”上的匹配`
匹配自我{
//不能拥有尾巴,因为“self”是借来的;
//取而代之的是引用尾部
Cons(u,ref tail)=>1+tail.len(),
//基本情况:空列表的长度为零
零=>0
}
}
//以(堆分配的)字符串形式返回列表的表示形式
fn字符串化(&self)->字符串{
匹配自我{
反面(正面、反面)=>{
//'format!'类似于'print!`,但返回一个堆
//已分配字符串,而不是打印到控制台
格式!(“{},{}”,head,tail.stringify())
},
零=>{
格式!(“无”)
},
}
}
}
fn main(){
//创建一个空的链表
让mut list=list::new();
//附加一些元素
list=list.prepend(1);
list=list.prepend(2);
list=list.prepend(3);
//显示列表的最终状态
println!(“链表的长度:{}”,list.len());
println!(“{}”,list.stringify());
}
如何可视化此代码的堆栈和堆
据我所知,prepend
拥有列表的所有权,在堆中分配空间,并将列表移动到堆中。当prepend
完成时,它将新创建的列表移动(赋予所有权)到外部变量
这是正确的吗
第一个列表::新返回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解除分配该变量,它也将解除分配该资源。这是正确的吗 Box
表示堆上某处的Foo
实例,由Box
对象管理和拥有
因此,对于列表,其最终值为:
let list=Cons(3,Box::new)(Cons(2,Box::new)(Cons(1,Box::new(Nil '))))
拥有一个list
对象,该对象是枚举的list
变体,拥有一个值Cons
的3
和一个u32
框
- 此
管理并拥有一个框
实例:一个列表
变量,它拥有一个Cons
值和一个其他2
框
- 第二个
管理并拥有一个框
实例:一个列表
变量,它拥有一个Cons
值和一个1
框
- 最后一个
管理并拥有一个框
实例:一个列表
变量Nil
框
的内容可能拥有其他框
的内容,当框
被销毁时,它将正确销毁其内容,而该内容本身也会正确销毁其内容,直到所属树的底部
// 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());
}