【问题标题】:Trie: cannot borrow `_` as mutable more than once at a timeTrie:不能一次多次借用`_`作为可变的
【发布时间】:2020-10-31 23:52:41
【问题描述】:

我想为 Trie 实现一些基本的方法。

use std::collections::HashMap;

#[derive(Debug)]
struct TrieNode {
    chs: HashMap<char, TrieNode>,
    value: Option<i32>,
}

#[derive(Debug)]
struct Trie {
    root: TrieNode,
}

impl Trie {
    fn new() -> Trie {
        Trie {
            root: TrieNode {
                chs: HashMap::new(),
                value: None,
            },
        }
    }

    fn add_string(&mut self, string: String, value: i32) {
        let mut current_node = &mut self.root;
        for c in string.chars() {
            current_node = current_node.chs.entry(c).or_insert(TrieNode {
                chs: HashMap::new(),
                value: None,
            });
        }
        current_node.value = Some(value);
    }

    fn delete(&mut self, key: &String) -> Option<i32> {
        if key.is_empty() {
            // if key is empty, no need to delete
            return None;
        }
        let mut current_node = &mut self.root;
        for (ind, ch) in key.chars().enumerate() {
            match current_node.chs.get_mut(&ch) {
                Some(node) => {
                    if ind < key.len() - 1 {
                        current_node = node;
                    }
                }
                None => return None,
            }
        }
        // here current_node is actually the previous node of the deleted node
        let temp = current_node.chs.remove(&key.chars().last().unwrap());
        match temp {
            Some(node) => node.value,
            None => None,
        }
    }
}

delete 方法是删除一个键(从一个 Trie 中)并返回与该键对应的值。但是,我收到以下错误。

error[E0499]: cannot borrow `current_node.chs` as mutable more than once at a time
   --> src/main.rs:118:19
    |
118 |             match current_node.chs.get_mut(&ch) {
    |                   ^^^^^^^^^^^^^^^^ mutable borrow starts here in previous iteration of loop

【问题讨论】:

    标签: data-structures rust trie


    【解决方案1】:

    我不确定借用检查器在哪里出错,但您可以通过提升 if 检查来修复它:

        let mut current_node = &mut self.root;
        for (ind, ch) in key.chars().enumerate() {
            if ind < key.len() - 1 {
                match current_node.chs.get_mut(&ch) {
                    Some(node) => {
                        current_node = node;
                    }
                    None => return None,
                }
            }
        }
    

    即使检查叶节点是否存在,它也会跳过,但您的 remove( 匹配已经涵盖了这种情况。


    另外,您的ind &lt; key.len() - 1 检查假定最后一个字符是ascii。您的用例可能是这样,但如果不是,您可以使用 this answer 迭代直到倒数第二个字符。

    【讨论】:

    • 您的答案完美无缺!太感谢了。但是我不明白为什么它可以通过调整if语句的位置来解决问题,你能解释一下吗?
    • @SpecialYong 我无法解释为什么原始表格不起作用。我已经asked a question 了;希望它得到一个答案。如果此答案解决了您的问题,请考虑投票和/或接受它。
    【解决方案2】:

    正如错误消息所解释的,您不能一次多次借用一个可变值 (current_node.chs)。

    一种解决方案是为TrieNode 派生Clone 特征。 Clone 是显式复制对象能力的共同特征:

    #[derive(Debug, Clone)]
    struct TrieNode {
        chs: HashMap<char, TrieNode>,
        value: Option<i32>,
    }
    

    现在你可以克隆它,而不是借用self.root

    fn delete(&mut self, key: &String) -> Option<i32> {
      if key.is_empty() { 
        return None
      }
      // clone `self.root`
      let mut current_node = self.root.clone();
      for (ind, ch) in key.chars().enumerate() {
      match current_node.chs.get_mut(&ch) {
        Some(node) => {
          if ind < key.len() - 1 {
          // clone `node`
            current_node = node.clone();
          }
        // ...
    

    如果性能是一个问题,那么克隆可能不是最好的主意。但是,它仍然是一种选择,可能适合也可能不适合您的用例。

    【讨论】:

    • 克隆会满足编译器的要求,但是当目标只是删除一个节点时,复制整个 trie(并为访问的每个 subtrie 再次复制)将是相当极端的
    • @kmdreko 如果性能是一个问题,我同意克隆不是最好的主意。但是,它仍然是一个选项,可能适用于操作的用例,也可能不适用。我在回答中添加了关于性能的注释
    • 这个方案虽然编译成功,返回了正确的值,但恐怕没有删除节点。它只是删除了复制的 Trie 中的节点,对吧?
    猜你喜欢
    • 1970-01-01
    • 2023-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多