Удобна функция, която ни позволява да разменим две стойности:
use std::mem;
let head = mem::replace(&mut self.head, Link::Empty)
self.head
, като слагаме някаква "празна" стойност като заместител.По-четим и удобен за използване вариант на предната функция за Option
let head = self.head.take();
// Превежда се отдолу до:
let head = Option::take(&mut self.head);
let head = std::mem::replace(&mut self.head, None);
Трябва self
да е взето или като mut self
, или &mut self
Метода map
се използва често когато имаме Option
:
None
, просто не вика функцията/closure-а.Some(val)
, вика функцията върху val
и я пакетира отново в `Some`.pub fn peek(&self) -> Option<&T> {
self.head.as_ref().map(|node| &node.elem)
}
Map обаче взема ownership! Метода as_ref
Конвертира Option<T>
в Option<&T>
, което ни позволява да достъпим вътрешната стойност по reference (ако изобщо има такава).
Итерирането по този начин включва вземане на вътрешния &Node
изпод Box-а. Това може да изглежда объркващо...
pub fn iter(&self) -> Iter<T> {
Iter {
current: self.head.as_ref().map(|node| &**node),
}
}
Винаги трябва да мислим за типовете! В случая имаме:
Option<Box<Node<T>>> // в списъка.
Option<&Node<T>> // в итератора. Не искаме Box, защото не искаме ownership
// self.head: Option<Box<Node<T>>>
// current: Option<&Node<T>>
let current = self.head.as_ref().map(|node| &**node);
// node: &Box<Node<T>>
// *node: *&Box<Node<T>> -> Box<Node<T>>
// **node: *Box<Node<T>> -> *&Node<T> -> Node<T>
// &**node: &Node<T>
Алтернативно, функцията Box::as_ref
ни дава същия процес с по-малко perl-like код:
let mut current = self.head.as_ref().map(|node| Box::as_ref(node));
// Или, за по-кратко:
let mut current = self.head.as_ref().map(Box::as_ref);
let mut current = self.head.as_mut().map(|node| &mut **node);
// Или
let mut current = self.head.as_mut().map(Box::as_mut);
Благодарение на всичките safety check-ове, спокойно можем и да си вземем mutable reference, с почти същия код.
Тези три имплементации на peek
са еквивалентни:
pub fn peek(&self) -> Option<&T> {
self.head.as_ref().map(|node| &node.elem)
}
pub fn peek(&self) -> Option<&T> {
match self.head {
None => None,
Some(ref node) => Some(&node.elem)
}
}
pub fn peek(&self) -> Option<&T> {
let node = self.head.as_ref()?;
Some(&node.elem)
}
Дали ще ползвате map, експлицитен pattern-matching, или ?
оператора е предимно въпрос на предпочитание. Не всички варианти са използваеми на всички места, разбира се.
Напълно е възможно да започнете с експлицитен pattern-matching, и да видите, че можете да си опростите кода значително с един map. Или да "извадите" стойност от option рано в метода и оттам нататък да работите безопасно с нея.
Експериментирайте, за да откриете с какво се чувствате най-комфортни. Правете го редовно -- силно е вероятно предпочитанията ви да се променят с времето.