如何理解 rust 的单向链表( 二 )


好了 , 这样对象组成就定义完成了 , 接下来就是给这个List对象实现一些方法了 , 

如何理解 rust 的单向链表

文章插图
需要实现的方法:
1. 构造方法new()2. 展示列表show()3. 添加元素方法push()4. 删除尾部元素方法pop()5. 搜索节点查询某个值get()6. 通过某个值遍历列表删除某个值(节点)remove()7. 链表长度len() , 如果需要记录链表长度 , 那么List对象还需要添加一个size属性 , 即:struct List {size: u32,head: Next,}8. 取最上面一个节点:pick()9. 用于遍历查询下一个元素:next() 。。。。
需要知道 , 链表元素push是往头(第一个)元素上添加 , pop也是从头取出删除 , 就和栈一样 , 先入后出 。
具体的过程就是:首先创建一个节点node , 将新Node的next指向原head指向的地方 , 最后将List的head指向新的Node
impl List {fn new() -> Self {List{// 给头添加一个空元素 , 空元素里面是没值的 , 这样就有一个头了head: Some(Box::new(Node { value: 0, next: None })),}}fn push(&mut self, value: i32) {// 创建node对象 , 需要了解的是 , 当插入的时候 , 需要将这个节点的下一个元素指向原来List的头 , 这样才是在头部插入let new_node = Box::new(Node{ value, next: self.head });// 将self.head重新指向该节点self.head = Some(new_node);}}
很简单是吧 , 但是很不好意思 , 这是rust , 你这么写是不会通过编译的 , 因为所有权问题:self.head是不允许移动的
那咋办呢 , 那我直接写成这样就不成了:
let= Box::new(Node{ value, next: None });
那么问题来了 , 可以通过编译 , 但是如果你插入该节点时 , 这个List已经有元素了 , 就会导致之前的元素就没了 , 因为你next为None了呀 , 所以 , 还是必须要通过更改指针来解决 。
而有一个方法:take(Takes the value out of the ,a None in its place)
就是从该中取出Some(?)值 , take完事了这时self.head就是None了 , 你就会想 , 这不还是放进去一个None了吗 , 但是你想想 , 在take的时候 , 我们把之前的head拿到了 , 并且把值交给了 , 而不是和刚刚上面编译报错的例子一样直接丢弃了 。
注 , rust语言圣经用的是一个方法 , 一样 , 就是把self.head数据取出来 , 然后换成一个空 , 然后模式匹配取出来的这个 , 如果是Some就说明链表原来有值 , 现在要插入新值 , 因此要指针重新指定(a) , 而如果是None说明原来没值 , 当前节点时一个节点 , 这样啥都不要弄了
而这里使用take方法就比优雅的多 , 因为直接取出放进去即可 , 不用关心取出来的是不是一个None , 反正如果是None , 就说明是第一个元素呗 。
第一阶段代码(仅包含push  , pop, 和一些peak方法 , 其中 show方法只是用来检查数据的 , 实际这么打印是没有任何意义的):
type Next = Option;#[derive(Debug)]struct List {size: u32,head: Next,}#[derive(Debug, PartialEq)]struct Node {value: i32,next: Next,}impl List {fn new() -> Self {List {size: 0,// 给头添加一个空元素 , 空元素里面是没值的 , 这样就有一个头了head: Some(Box::new(Node { value: 0, next: None })),}}fn show(&self) {println!("list is {:?}", self);}fn push(&mut self, value: i32) {// 创建node对象 , 需要了解的是 , 当插入的时候 , 需要将这个节点的下一个元素指向原来List的头 , 这样才是在头部插入// Option.take()的方法描述的很清楚 , 取出Option中的Some(?) , 然后把原来的对象设置为Nonelet new_node = Box::new(Node { value, next: self.head.take() });// 这时self.head就是空了 , 然后重新赋值 , 将self.head指向该节点assert_eq!(self.head, None);self.head = Some(new_node);// 此时是添加操作 , 因此元素长度+1self.size += 1;}fn pop(&mut self) -> Option