【问题标题】:Optionally push item to Vec or return existing item [duplicate]可选择将项目推送到 Vec 或返回现有项目 [重复]
【发布时间】:2019-04-26 01:42:54
【问题描述】:

我有一个函数可以从 Vec 返回对现有项目的引用,或者将新项目推送到 Vec 并返回对该现有项目的引用。我创建了一个基本示例来说明我想要做什么:

struct F {
    x: Vec<Vec<String>>,
}

impl F {
    fn foo(&mut self, s: String) -> &[String] {
        for strings in &self.x {
            if strings.contains(&s) {
                return &strings;
            }
        }

        self.x.push(vec![s]);

        &self.x[self.x.len() - 1]
    }
}

但是当我尝试编译这个时,我得到一个关于生命周期的错误:

error[E0502]: cannot borrow `self.x` as mutable because it is also borrowed as immutable
  --> src/lib.rs:13:9
   |
6  |     fn foo(&mut self, s: String) -> &[String] {
   |            - let's call the lifetime of this reference `'1`
7  |         for strings in &self.x {
   |                        ------- immutable borrow occurs here
8  |             if strings.contains(&s) {
9  |                 return &strings;
   |                        -------- returning this value requires that `self.x` is borrowed for `'1`
...
13 |         self.x.push(vec![s]);
   |         ^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here

我不明白这个错误,因为在我看来,第 7 行的不可变借用保证在第 13 行不再存在,因为函数要么在第 13 行之前返回,要么 for 循环已经结束,借款应该以它结束。我错过了什么?

【问题讨论】:

  • 我认为这是一些应该工作但没有工作的代码的一个很好的例子;也许向 Rust 编译器提出问题?我原以为 NLL 会解决这个问题。

标签: rust


【解决方案1】:

我认为这是当前借用检查器的限制,您可以这样做:

struct F {
    x: Vec<Vec<String>>,
}

impl F {
    fn foo(&mut self, s: String) -> &[String] {
        let ret = self.x.iter().position(|strings| strings.contains(&s));

        if let Some(ret) = ret {
            &self.x[ret]
        } else {
            self.x.push(vec![s]);
            &self.x.last().unwrap()
        }
    }
}

【讨论】:

    【解决方案2】:

    Stargateur is right 和借用检查器无法证明您的代码是正确的。我们必须帮助它。

    另一种可能性是在迭代 Vecs 时使用索引。

    struct F {
        x: Vec<Vec<String>>,
    }
    
    impl F {
        fn foo(&mut self, s: String) -> &[String] {
            for (i, strings) in self.x.iter().enumerate() {
                if strings.contains(&s) {
                    return &self.x[i];
                }
            }
    
            self.x.push(vec![s]);
            self.x.last().unwrap()
        }
    }
    

    (也可以使用slice::last而不是手动获取索引。更清楚你要做什么)。

    【讨论】:

      猜你喜欢
      • 2013-06-21
      • 2020-11-02
      • 1970-01-01
      • 2021-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-01
      • 1970-01-01
      相关资源
      最近更新 更多