Функция push_sort связанного списка Rust

Я пытаюсь реализовать свой собственный 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;
        }
    }

«Если позволить некоторым (голове)» более идиоматично.

pm100 28.02.2024 15:51

Вместо чего? Мне не нравилось использовать слишком много is_none() или unwrap(), но я не мог заменить их на if Some и сопоставить, не вызывая проблем.

nem0z 28.02.2024 16:04

Обязательный вопрос по связанному списку: вы читали книгу слишком много списков?

user4815162342 28.02.2024 16:09

Да, я сделал (части с 1 по 4), но я решил пока не указывать время жизни, и это не помогло мне для этой конкретной функции.

nem0z 28.02.2024 16:22

«Более идиоматично» не по теме Stack Overflow, вы можете спросить на codereview.stackexchange.com.

Chayim Friedman 28.02.2024 20:26
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
0
5
55
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вам не нужны 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?

nem0z 28.02.2024 16:30
* просто разыменовывает остальную часть выражения в левой части присваивания, что означает присвоение цели ссылки, а не самой переменной. Таким образом, в этом коде он меняет последние Nodes .next (потому что именно здесь цикл while выпадает) вместо изменения current.
cafce25 28.02.2024 16:34
std::mem::replace заменяет и возвращает то, что стоит за первым аргументом, на то, что вы передаете в качестве второго аргумента. Option::take по сути std::mem::replace(&mut opt, None).
cafce25 28.02.2024 16:53

Хорошо, насколько я понимаю, current — это изменяемая переменная, в которой хранится изменяемая ссылка, * используется для обновления переменной, «указанной» текущим, вместо изменения текущего значения, то есть «указателя»?

nem0z 28.02.2024 16:53

Другие вопросы по теме