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

<&'a Node> --> Option<&'a mut Node>info: Option<&'a mut Node>,}impl<'a, T> Iterator for MutIter<'a, T> {type Item = &'a T; // 最后这里也要改成mut的: type Item = &'a mut T;fn next(&mut self) -> Option {// 实际这么写是会报错的 , 因为这里的self.info中的&mut T是不可Copy的 , 因此这里就会move , // cannot move out of `self.info` which is behind a mutable reference , 因为可变的引用self压根不拥有info// 那肯定就更不可能move info了 , 因此这里使用take() , 将数据临时取出再放进去一个空self.info.map(|node|{self.info = node.next.as_deref_mut();&node.value // 当然这里最后也必须是mut的 , 不然返回的数据不可修改: &mut node.value })}}impl List {pub fn iter_mut(&mut self) -> IterMut {// 很清楚 , 这个和as_deref()方法返回的值一样 , 不过这个值是mut的IterMut{ info: self.head.as_deref_mut() }}}
注: 为什么可变的引用(&mut T)不可以Copy , 因为一个引用说白了就是一个指针 , 拷贝一个指针就是多一个指向某值的拷贝 , 而如果这个值是可变的 , 那很可能它在某次变化后它的地址就变了(比如vec元素增加的时候 , 超过cap值进行扩容 , 此时它会选一块新的内存地址 , 将原来的数据拷贝过去) , 这样就会产生悬垂引用 , 即一个指向无效内存的指针
最终part3完整的样子:
pub struct IterMut<'a, T> {info: Option<&'a mut Node>,}impl<'a, T> Iterator for IterMut<'a, T> {type Item = &'a mut T;fn next(&mut self) -> Option {// 由于self.info中的&mut T是没有满足copy的trait , 因此这里就会move , 但是我们又不能move这个值// 这里使用self.info.take()将self.info临时拿出来 , 然后放进去一个None , 然后在对拿出来的数据做map操作// 不用担心self.info变成None会指向空 , 因为里面会重新把下一个元素取出来放到这个self.info中self.info.take().map(|node| {self.info = node.next.as_deref_mut();&mut node.value})}}impl List {pub fn iter_mut(&mut self) -> IterMut {IterMut{ info: self.head.as_deref_mut() }}}// 测试代码#[test]fn iter_mut() {let mut list = List::new();list.push(1); list.push(2); list.push(3);let mut iter = list.iter_mut();assert_eq!(iter.next(), Some(&mut 3));assert_eq!(iter.next(), Some(&mut 2));assert_eq!(iter.next(), Some(&mut 1));}
最终的代码
【如何理解 rust 的单向链表】type Next = Option>;#[derive(Debug)]struct List {size: u32,head: Next,}#[derive(Debug, PartialEq)]struct Node {value: T,next: Next,}impl List {fn new() -> Self {List {size: 0,// 给头添加一个空元素 , 空元素里面是没值的 , 这样就有一个头了head: None,}}fn push(&mut self, value: T) {// 创建node对象 , 需要了解的是 , 当插入的时候 , 需要将这个节点的下一个元素指向原来List的头 , 这样才是在头部插入// Option.take()的方法描述的很清楚 , 取出Option中的Some(?) , 然后把原来的对象设置为Nonelet new_node = Box::new(Node { value, next: self.head.take() });self.head = Some(new_node);// 此时是添加操作 , 因此元素长度+1self.size += 1;}fn pop(&mut self) -> Option {if self.size == 0 {panic!("no value to pop.")}//由于self.size == 0的情况已经考虑 , 因此就不需要match或if let的模式匹配 ,直接letlet node = self.head.take().unwrap();self.head = node.next;self.size -= 1;Some(node.value)}fn peek(&self) -> Option<&T> {if self.size == 0 {return None;}// map可以从一个Option中取到里面的数据 , 然后操作后再返回给Option进行包装// 就是他描述的:Maps an Option to Option