Я пытаюсь реализовать свой собственный Linkedlist в Rust (в учебных целях).
Структуры, которые я использую:
struct Node<T> {
value: T,
next: Option<Box<Node<T>>>,
}
impl<T> Node<T> {
pub fn new(val: T) -> Self {
return Node {
value: val,
next: None,
};
}
pub fn new_with_next(val: T, next: Option<Box<Node<T>>>) -> Self {
return Node {
value: val,
next: next,
};
}
}
struct List<T> {
head: Option<Box<Node<T>>>,
}
Я реализовал функцию, позволяющую переместить элемент в нужное место в отсортированном списке (мы предполагаем, что это так). Он работает нормально (после долгих часов борьбы), но как новичок в Rust и поскольку Rust сильно отличается от других языков, которые я использую, мне интересно, нет ли более идиоматического способа реализовать это в Rust.
fn push_sort(&mut self, val: T) where T: std::cmp::PartialOrd {
match &mut self.head {
Some(head) => {
if head.value >= val {
self.head = Some(Box::new(Node::new_with_next(val, self.head.take())));
return;
}
},
None => {
self.head = Some(Box::new(Node::new(val)));
return;
}
};
let mut current = &mut self.head;
while let Some(node) = current {
if node.next.is_none() {
node.next = Some(Box::new(Node::new(val)));
return;
}
if val < node.next.as_ref().unwrap().value {
node.next = Some(Box::new(Node::new_with_next(val, node.next.take())));
return;
}
current = &mut node.next;
}
}
Вместо чего? Мне не нравилось использовать слишком много is_none() или unwrap(), но я не мог заменить их на if Some и сопоставить, не вызывая проблем.
Обязательный вопрос по связанному списку: вы читали книгу слишком много списков?
Да, я сделал (части с 1 по 4), но я решил пока не указывать время жизни, и это не помогло мне для этой конкретной функции.
«Более идиоматично» не по теме Stack Overflow, вы можете спросить на codereview.stackexchange.com.

Вам не нужны match и while let, все это можно сделать в одном цикле, то же самое для проверки узлов на предмет наличия Some или None в теле цикла и его состояния:
fn push_sort(&mut self, val: T)
where
T: std::cmp::PartialOrd,
{
let mut current = &mut self.head;
while let Some(c) = current {
if c.value >= val {
let old = std::mem::replace(c, Box::new(Node::new(val)));
c.next = Some(old);
return;
}
current = &mut c.next;
}
*current = Some(Box::new(Node::new(val)));
}
Хорошо, спасибо, это очень хорошая работа. Я предполагаю, что std::mem::replace эквивалентно Options .took() ? Просто вопрос: как работает *, многие использовали это для вещей, которые не реализовали Copy или Clone?
* просто разыменовывает остальную часть выражения в левой части присваивания, что означает присвоение цели ссылки, а не самой переменной. Таким образом, в этом коде он меняет последние Nodes .next (потому что именно здесь цикл while выпадает) вместо изменения current.
std::mem::replace заменяет и возвращает то, что стоит за первым аргументом, на то, что вы передаете в качестве второго аргумента. Option::take по сути std::mem::replace(&mut opt, None).
Хорошо, насколько я понимаю, current — это изменяемая переменная, в которой хранится изменяемая ссылка, * используется для обновления переменной, «указанной» текущим, вместо изменения текущего значения, то есть «указателя»?
«Если позволить некоторым (голове)» более идиоматично.