Не могу заимствовать *self как неизменяемый, но не могу найти обходной путь

Итак, у меня есть вышеуказанная ошибка в строке 17, которую я понимаю, но не нашел хорошего способа ее решения:

struct Node {
    node_type: NodeType
}

enum NodeType {
    Inner([Box<Node>; 16]),
    Leaf(Vec<usize>)
}

impl Node {
    fn foo(&mut self) {
        match &mut self.node_type {
            NodeType::Leaf(_content) => {
                // Mutate content
            },
            NodeType::Inner(children) => {
                let index = self.compute_index();
                let child = &mut children[index];
                child.foo();
            }
        }
    }

    fn compute_index(&self) -> usize {
        // compute something
        0
    }
}

Детская площадка

Мне нужно, чтобы self был изменяемым, чтобы изменять его содержимое в случае Leaf. Я мог бы скопировать код из compute_index() в свою функцию foo(), но это сделало бы функцию foo() излишне длинной, и код внутри compute_index() сам по себе будет выглядеть как отдельная семантическая единица.

Я также мог бы переместить вызов в compute_index() над оператором match, но мне не нужно выполнять его во всех ответвлениях сопоставления, поэтому в этом случае это приведет к ненужным вычислениям и тоже не кажется правильным.

Я думал об этом довольно долго, но не мог придумать, как избавиться от этой ошибки, не ухудшив при этом свой код. Есть ли у кого-нибудь идеи, как избавиться от ошибки, не ухудшив код?

Зависит ли compute_index() от children?

Chayim Friedman 17.04.2024 12:10

Нет

David 17.04.2024 17:55

Тогда вы можете сделать так, чтобы он занимал только необходимые поля, а не все self. В качестве альтернативы, если это имеет больше смысла, разделите структуру NonChildren на Node и сделайте compute_index() методом NonChildren.

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

Ответы 1

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

Можете ли вы перетасовать все, чтобы вычислить индекс, прежде чем получать изменяемый заем?

impl Node {
    fn foo(&mut self) {
        if let NodeType::Leaf(_content) = &mut self.node_type {
            // Mutate content
            _content.push(42);
        } else {
            let index = self.compute_index();
            if let NodeType::Inner(children) = &mut self.node_type {
                let child = &mut children[index];
                child.foo();
            }
        }
    }

    fn compute_index(&self) -> usize {
        // compute something
        0
    }
}

Да, это хорошо работает. Второе if let кажется немного ненужным, поскольку вы уже знаете, что это Inner, но это кажется лучшим решением, спасибо! :)

David 17.04.2024 11:17

Проблема match в том, что он держит нагрузку на все тело. Возможно, вы также можете сохранить совпадение как есть и условно вычислить индекс перед совпадением с помощью let index = if let NodeType::Inner(_) = self.node_type { self.compute_index() } else { 0 }; и использовать индекс только в одной ветви сопоставления, но это своего рода утечка инкапсуляции.

Alexey S. Larionov 17.04.2024 11:26

Верно, но я предпочитаю ваше оригинальное решение, потому что мне не нравится объявлять переменные в более широкой области, чем они используются/необходимы.

David 17.04.2024 17:58

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

Возвращает принадлежащее значение и ссылку на значение
Заимствовать некоторое изменяемое значение дважды, если известно, что изменяемое значение является неизменяемым
Почему мой параметр типа в этом блоке impl не ограничен?
Какую структуру можно создать, чтобы избежать использования RefCell?
Почему средство проверки заимствований в Rust жалуется при использовании итератора, возвращаемого из метода, но не при непосредственном использовании итератора Vec?
Как лучше всего распараллелить код, изменяя несколько фрагментов одного и того же вектора Rust?
Rust: вернуть неизменяемый заем после изменения
Каким был бы идиоматический способ Rust иметь вектор признаков с псевдонимами для отдельных элементов вектора?
Как вернуть ссылку на значение внутри Rc<RefCell<Node>>
Развернуть вариант перечисления и вернуть либо принадлежащее ему значение, либо ссылку