Всякая всячина
Вы говорили, что хотите продуктового кода, нет?
Вот немного всякой всячины, чтобы получилась «хорошая» коллекция:
impl<T> LinkedList<T> {
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn clear(&mut self) {
// О, смотрите, это снова drop
while let Some(_) = self.pop_front() { }
}
}
Теперь реализуем набор типажей, которые должны быть у коллекции:
impl<T> Default for LinkedList<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: Clone> Clone for LinkedList<T> {
fn clone(&self) -> Self {
let mut new_list = Self::new();
for item in self {
new_list.push_back(item.clone());
}
new_list
}
}
impl<T> Extend<T> for LinkedList<T> {
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
for item in iter {
self.push_back(item);
}
}
}
impl<T> FromIterator<T> for LinkedList<T> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let mut list = Self::new();
list.extend(iter);
list
}
}
impl<T: Debug> Debug for LinkedList<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self).finish()
}
}
impl<T: PartialEq> PartialEq for LinkedList<T> {
fn eq(&self, other: &Self) -> bool {
self.len() == other.len() && self.iter().eq(other)
}
fn ne(&self, other: &Self) -> bool {
self.len() != other.len() || self.iter().ne(other)
}
}
impl<T: Eq> Eq for LinkedList<T> { }
impl<T: PartialOrd> PartialOrd for LinkedList<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.iter().partial_cmp(other)
}
}
impl<T: Ord> Ord for LinkedList<T> {
fn cmp(&self, other: &Self) -> Ordering {
self.iter().cmp(other)
}
}
impl<T: Hash> Hash for LinkedList<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.len().hash(state);
for item in self {
item.hash(state);
}
}
}
Я написала весь код с нуля, а не просто скопировала из стандартной библиотеки. Здесь всё такое интересное и я определённо помню все тонкости ручной реализации Hash. Да, я постоянно думаю об этом...
Ладно, здесь действительно есть пара моментов, на которые надо обратить внимание.
Во-первых, неприятный конфликт пространств имён. По какой-то причине в стандартной библиотеке теперь есть макросы с именами Hash и Debug, так что если вы не импортировали типажи, вы получите поистине таинственные ошибки о макросах вместо простого «типаж не найден».
Другая интересная вещь касается самого Hash.
Вы видите, что мы вызываем hash у len?
Это на самом деле важно!
Если коллекции не учитывают свою длину при вычислении хеша, они могут случайно стать уязвимыми для коллизии префиксов.
Например, чем отличаются ["he", "llo"] и ["hello"]?
Если при вычислении хеша вы не используете длину или какой-то разделитель, то ничем!
Слишком высокая вероятность коллизий при вычислении хеша может привести к большим неприятностям, так что просто напишите правильно!
Хорошо, вот наш текущий код:
#![allow(unused)] fn main() { use std::cmp::Ordering; use std::fmt::{self, Debug}; use std::hash::{Hash, Hasher}; use std::iter::FromIterator; use std::ptr::NonNull; use std::marker::PhantomData; pub struct LinkedList<T> { front: Link<T>, back: Link<T>, len: usize, _boo: PhantomData<T>, } type Link<T> = Option<NonNull<Node<T>>>; struct Node<T> { front: Link<T>, back: Link<T>, elem: T, } pub struct Iter<'a, T> { front: Link<T>, back: Link<T>, len: usize, _boo: PhantomData<&'a T>, } pub struct IterMut<'a, T> { front: Link<T>, back: Link<T>, len: usize, _boo: PhantomData<&'a mut T>, } pub struct IntoIter<T> { list: LinkedList<T>, } impl<T> LinkedList<T> { pub fn new() -> Self { Self { front: None, back: None, len: 0, _boo: PhantomData, } } pub fn push_front(&mut self, elem: T) { // БЕЗОПАСНОСТЬ: это связный список, что вы делаете? unsafe { let new = NonNull::new_unchecked(Box::into_raw(Box::new(Node { front: None, back: None, elem, }))); if let Some(old) = self.front { // Вставляем новый передний узел перед старым (*old.as_ptr()).front = Some(new); (*new.as_ptr()).back = Some(old); } else { // Если переднего узла нет, у нас пустой список и нам надо // установить и значение заднего узла. debug_assert!(self.back.is_none()); debug_assert!(self.front.is_none()); debug_assert!(self.len == 0); self.back = Some(new); } // Этот код выполняется всегда! self.front = Some(new); self.len += 1; } } pub fn push_back(&mut self, elem: T) { // БЕЗОПАСНОСТЬ: это связный список, что вы делаете? unsafe { let new = NonNull::new_unchecked(Box::into_raw(Box::new(Node { back: None, front: None, elem, }))); if let Some(old) = self.back { // Вставляем новый задний узел перед старым (*old.as_ptr()).back = Some(new); (*new.as_ptr()).front = Some(old); } else { // Если заднего узла нет, у нас пустой список и нам надо // установить и значение переднего узла. self.front = Some(new); } // Этот код выполняется всегда! self.back = Some(new); self.len += 1; } } pub fn pop_front(&mut self) -> Option<T> { unsafe { // Будем что-то делать, только если у списка есть передний узел. self.front.map(|node| { // Возвращаем к жизни Box, так что можно извлечь и уничтожить его // значение (Box магически делает это за нас). let boxed_node = Box::from_raw(node.as_ptr()); let result = boxed_node.elem; // Делаем следующий узел новым передним узлом. self.front = boxed_node.back; if let Some(new) = self.front { // Убираем ссылку переднего узла на удалённый узел. (*new.as_ptr()).front = None; } else { // Если передний узел равен null, значит, список пустой! debug_assert!(self.len == 1); self.back = None; } self.len -= 1; result // Здесь Box неявным образом освобождается, потому что больше нет T. }) } } pub fn pop_back(&mut self) -> Option<T> { unsafe { // Будем что-то делать, только если у списка есть задний узел. self.back.map(|node| { // Возвращаем к жизни Box, так что можно извлечь и уничтожить его // значение (Box магически делает это за нас). let boxed_node = Box::from_raw(node.as_ptr()); let result = boxed_node.elem; // Делаем следующий узел новым задним узлом. self.back = boxed_node.front; if let Some(new) = self.back { // Убираем ссылку заднего узла на удалённый узел. (*new.as_ptr()).back = None; } else { // Если задний узел равен null, значит, список пустой! self.front = None; } self.len -= 1; result // Здесь Box неявным образом освобождается, потому что больше нет T. }) } } pub fn front(&self) -> Option<&T> { unsafe { self.front.map(|node| &(*node.as_ptr()).elem) } } pub fn front_mut(&mut self) -> Option<&mut T> { unsafe { self.front.map(|node| &mut (*node.as_ptr()).elem) } } pub fn back(&self) -> Option<&T> { unsafe { self.back.map(|node| &(*node.as_ptr()).elem) } } pub fn back_mut(&mut self) -> Option<&mut T> { unsafe { self.back.map(|node| &mut (*node.as_ptr()).elem) } } pub fn len(&self) -> usize { self.len } pub fn is_empty(&self) -> bool { self.len == 0 } pub fn clear(&mut self) { // Oh look it's drop again while let Some(_) = self.pop_front() { } } pub fn iter(&self) -> Iter<T> { Iter { front: self.front, back: self.back, len: self.len, _boo: PhantomData, } } pub fn iter_mut(&mut self) -> IterMut<T> { IterMut { front: self.front, back: self.back, len: self.len, _boo: PhantomData, } } pub fn into_iter(self) -> IntoIter<T> { IntoIter { list: self } } } impl<T> Drop for LinkedList<T> { fn drop(&mut self) { // Вызываем pop, пока есть элементы while let Some(_) = self.pop_front() { } } } impl<T> Default for LinkedList<T> { fn default() -> Self { Self::new() } } impl<T: Clone> Clone for LinkedList<T> { fn clone(&self) -> Self { let mut new_list = Self::new(); for item in self { new_list.push_back(item.clone()); } new_list } } impl<T> Extend<T> for LinkedList<T> { fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) { for item in iter { self.push_back(item); } } } impl<T> FromIterator<T> for LinkedList<T> { fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self { let mut list = Self::new(); list.extend(iter); list } } impl<T: Debug> Debug for LinkedList<T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self).finish() } } impl<T: PartialEq> PartialEq for LinkedList<T> { fn eq(&self, other: &Self) -> bool { self.len() == other.len() && self.iter().eq(other) } fn ne(&self, other: &Self) -> bool { self.len() != other.len() || self.iter().ne(other) } } impl<T: Eq> Eq for LinkedList<T> { } impl<T: PartialOrd> PartialOrd for LinkedList<T> { fn partial_cmp(&self, other: &Self) -> Option<Ordering> { self.iter().partial_cmp(other) } } impl<T: Ord> Ord for LinkedList<T> { fn cmp(&self, other: &Self) -> Ordering { self.iter().cmp(other) } } impl<T: Hash> Hash for LinkedList<T> { fn hash<H: Hasher>(&self, state: &mut H) { self.len().hash(state); for item in self { item.hash(state); } } } impl<'a, T> IntoIterator for &'a LinkedList<T> { type IntoIter = Iter<'a, T>; type Item = &'a T; fn into_iter(self) -> Self::IntoIter { self.iter() } } impl<'a, T> Iterator for Iter<'a, T> { type Item = &'a T; fn next(&mut self) -> Option<Self::Item> { // Хотя условие self.front == self.back кажется очевидным, // оно не подходит для возврата последнего элемента! Подобный код // работает только с массивами из-за указателя «на элемент, следующий // за последним» if self.len > 0 { // Мы могли бы извлечь значение из front, но так быстрее и безопаснее self.front.map(|node| unsafe { self.len -= 1; self.front = (*node.as_ptr()).back; &(*node.as_ptr()).elem }) } else { None } } fn size_hint(&self) -> (usize, Option<usize>) { (self.len, Some(self.len)) } } impl<'a, T> DoubleEndedIterator for Iter<'a, T> { fn next_back(&mut self) -> Option<Self::Item> { if self.len > 0 { self.back.map(|node| unsafe { self.len -= 1; self.back = (*node.as_ptr()).front; &(*node.as_ptr()).elem }) } else { None } } } impl<'a, T> ExactSizeIterator for Iter<'a, T> { fn len(&self) -> usize { self.len } } impl<'a, T> IntoIterator for &'a mut LinkedList<T> { type IntoIter = IterMut<'a, T>; type Item = &'a mut T; fn into_iter(self) -> Self::IntoIter { self.iter_mut() } } impl<'a, T> Iterator for IterMut<'a, T> { type Item = &'a mut T; fn next(&mut self) -> Option<Self::Item> { // Хотя условие self.front == self.back кажется очевидным, // оно не подходит для возврата последнего элемента! Подобный код // работает только с массивами из-за указателя «на элемент, следующий // за последним» if self.len > 0 { // Мы могли бы извлечь значение из front, но так быстрее и безопаснее self.front.map(|node| unsafe { self.len -= 1; self.front = (*node.as_ptr()).back; &mut (*node.as_ptr()).elem }) } else { None } } fn size_hint(&self) -> (usize, Option<usize>) { (self.len, Some(self.len)) } } impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { fn next_back(&mut self) -> Option<Self::Item> { if self.len > 0 { self.back.map(|node| unsafe { self.len -= 1; self.back = (*node.as_ptr()).front; &mut (*node.as_ptr()).elem }) } else { None } } } impl<'a, T> ExactSizeIterator for IterMut<'a, T> { fn len(&self) -> usize { self.len } } impl<T> Iterator for IntoIter<T> { type Item = T; fn next(&mut self) -> Option<Self::Item> { self.list.pop_front() } fn size_hint(&self) -> (usize, Option<usize>) { (self.list.len, Some(self.list.len)) } } impl<T> DoubleEndedIterator for IntoIter<T> { fn next_back(&mut self) -> Option<Self::Item> { self.list.pop_back() } } impl<T> ExactSizeIterator for IntoIter<T> { fn len(&self) -> usize { self.list.len } } #[cfg(test)] mod test { use super::LinkedList; #[test] fn test_basic_front() { let mut list = LinkedList::new(); // Пытаемся сломать пустой список assert_eq!(list.len(), 0); assert_eq!(list.pop_front(), None); assert_eq!(list.len(), 0); // Пытаемся сломать список из одного элемента list.push_front(10); assert_eq!(list.len(), 1); assert_eq!(list.pop_front(), Some(10)); assert_eq!(list.len(), 0); assert_eq!(list.pop_front(), None); assert_eq!(list.len(), 0); // Всё перемешиваем list.push_front(10); assert_eq!(list.len(), 1); list.push_front(20); assert_eq!(list.len(), 2); list.push_front(30); assert_eq!(list.len(), 3); assert_eq!(list.pop_front(), Some(30)); assert_eq!(list.len(), 2); list.push_front(40); assert_eq!(list.len(), 3); assert_eq!(list.pop_front(), Some(40)); assert_eq!(list.len(), 2); assert_eq!(list.pop_front(), Some(20)); assert_eq!(list.len(), 1); assert_eq!(list.pop_front(), Some(10)); assert_eq!(list.len(), 0); assert_eq!(list.pop_front(), None); assert_eq!(list.len(), 0); assert_eq!(list.pop_front(), None); assert_eq!(list.len(), 0); } } }