014 Learn the Drop of Rust's persistent linked list through the linked list

introduce

Video address: https://www.bilibili.com/video/av78062009/
Related source code: https://github.com/anonymousGiga/Rust-link-list

details

In this section, we implement the Drop of the persistent linked list. When we implemented the Drop of the mutable linked list before, we used the loop to recycle. If we adopt a unified method here, it will not work, because we share through Rc here, and we must wait for the reference count to be 0 to remove the data from Rc.

Implementation of Drop

Drop is implemented as follows:

//实现Drop
impl<T> Drop for List<T> {
	fn drop(&mut self) {
		let mut head = self.head.take();	
		while let Some(node) = head {
			if let Ok(mut node) = Rc::try_unwrap(node) {
				head = node.next.take();
			} else {
				break;
			}
		}
	}
}

The complete code is as follows:

use std::rc::Rc;
pub struct List<T> {
	head: Link<T>,
}

type Link<T> = Option<Rc<Node<T>>>;

struct Node<T> {
	elem: T,
	next: Link<T>,
}

impl<T> List<T> {
	pub fn new() -> Self {
		List { head: None }
	}

	pub fn append(&mut self, elem: T) -> List<T> {
		List { head: Some(Rc::new(Node {
			elem: elem,
			next: self.head.clone(),
		}))}	
	}

	pub fn tail(&self) -> List<T> {
		List { head: self.head.as_ref().and_then(|node| {
			node.next.clone()
		})}
	}

	pub fn head(&self) -> Option<&T> {
		self.head.as_ref().map(|node| &node.elem)
	}
}

//实现Iter
pub struct Iter<'a, T> {
	next: Option<&'a Node<T>>,
}

impl<T> List<T> {
	pub fn iter(&self) -> Iter<T> {
		Iter { next: self.head.as_deref() }
	}
}

impl<'a, T> Iterator for Iter<'a, T> {
	type Item = &'a T;

	fn next(&mut self) -> Option<Self::Item> {
		self.next.map(|node| {
			self.next = node.next.as_deref();
			&node.elem
		})
	}
}

//实现Drop
impl<T> Drop for List<T> {
	fn drop(&mut self) {
		let mut head = self.head.take();	
		while let Some(node) = head {
			if let Ok(mut node) = Rc::try_unwrap(node) {
				head = node.next.take();
			} else {
				break;
			}
		}
	}
}

#[cfg(test)]
mod test {
	use super::List;
	#[test]
	fn basics() {
		let mut list = List::new();
		assert_eq!(list.head(), None);

		let list = list.append(1).append(2).append(3);
		assert_eq!(list.head(), Some(&3));

		let list = list.tail();
		assert_eq!(list.head(), Some(&2));

		let list = list.tail();
		assert_eq!(list.head(), Some(&1));

		let list = list.tail();
		assert_eq!(list.head(), None);
	}

	#[test]
	fn iter() {
		let list = List::new().append(1).append(2).append(3);
		let mut iter = list.iter();

		assert_eq!(iter.next(), Some(&3));
		assert_eq!(iter.next(), Some(&2));
		assert_eq!(iter.next(), Some(&1));
	}
}

Guess you like

Origin blog.csdn.net/lcloveyou/article/details/120632671