【问题标题】:"Cannot move out of dereference `&`-pointer" with a vector带有向量的“无法移出取消引用`&`-pointer”
【发布时间】:2014-11-24 04:02:45
【问题描述】:

我现在正在试验 Rust,但我真的被各种各样的随机编译器错误绊倒了:

error: cannot move out of dereference of `&`-pointer
    return list[idx];
           ^~~~~~~~~

有问题的 sn-p 转载如下。 list 是一个单词列表,其想法是从列表中返回一个在一定长度内(在 minLength 和 maxLength 之间)的随机单词。因此,我生成一个随机 uint 并使用模数将其限制为列表的大小。然后我想检查一下这个词的长度是否正确,如果它返回它。

显然这不是最有效的方法,但我只是想要一些简单的东西来满足练习的需要。

fn get_a_word(list: Vec<String>, minLength: uint, maxLength: uint) -> String {
    loop {
        let idx = rand::random::<uint>() % list.len();
        if list[idx].len() > minLength && list[idx].len() < maxLength {
            return list[idx];
        }
    }
}

我已经对该错误消息的含义进行了一些研究,但似乎每个人都说这是在您处理 Option&lt;T&gt; retvals 时出现的,而不是试图从集合中获取价值。

这可能是一个非常简单的问题,但为什么 Rust 不让你从集合/向量/数组中返回一个值?

【问题讨论】:

    标签: rust


    【解决方案1】:

    一次只有一个东西可以拥有一个对象,而你在那里尝试做的事情会破坏这个不变量,因为你会在向量和返回位置都有你要返回的字符串。对于 Index::index 方法,list[idx] 或多或少地扩展为 *list.index(idx)(实际上它比 Index::indexIndexMut::index_mut 更复杂一点是根据上下文确定的,&amp;list[idx] 将是直接list.index(idx)list[idx].method()&amp;self-以methodlist.index(idx).method())。

    你有几个选择;这是三个:

    • 从列表中删除值,返回它。您拥有的其余Vec&lt;String&gt; 将被丢弃,因此除了正确的Strings 之外的所有Strings 最终都将被释放。

      return list.swap_remove(idx).unwrap();(比较swap_removeremove,前者效率更高,但改变了在这种情况下完全可以的顺序)代替return list[idx]; 可以做到这一点。

    • 克隆字符串。这效率较低,但可以认为是可以接受的。

      return list[idx].clone(); 可以做到这一点。

    • 在整个过程中使用切片和引用:这是最有效的方式,通常也是最惯用的方式。它很有效,因为它不涉及任何分配或解除分配或大值的移动。

      fn get_a_word(list: &[String], min_length: uint, max_length: uint) -> &str {
          loop {
              let idx = rand::random::<uint>() % list.len();
              if list[idx].len() > min_length && list[idx].len() < max_length {
                  return list[idx].as_slice();
              }
          }
      }
      

    【讨论】:

    • 你怎么能(快速)知道list[idx] 扩展为*list.index[&amp;idx]?虽然我同意这样做是有道理的,但我找不到相应的文档。实际上,您发布的文档中的函数定义fn index(&amp;'a self, index: Idx) -&gt; &amp;'a Self::Output 似乎并不要求index 是参考。
    • @mSSM:从那时起,它从按值引用获取索引发生了变化。现在,list[index] 等效于 *list.index(index)list.index(index)list.index_mut(index),具体取决于它的使用方式。 &amp;list[index] 是规范形式,意思是list.index(index),所以list[index] 就是*list.index(index) 是有道理的。它也受自动引用规则的约束,因此list[index].method_that_takes_self_by_ref() 等价于(&amp;list[index]).method_that_takes_self_by_ref()
    【解决方案2】:

    list[idx]*list.index(&amp;idx) 的简写。 index() 在被索引的值内返回一个借来的指针(这里是Vec)。你不能通过取消引用借来的指针来移动一个值(这里是String);这就像从拥有字符串的Vec 中“窃取”StringString 拥有堆上的分配;我们不能有两个 String 值引用相同的堆分配,否则它们会在它们被丢弃时都尝试释放它,这将导致双重释放。

    由于函数通过值接收Vec,这意味着Vec被移动到函数中,因此函数可以用它做任何我们想做的事情,因为它现在“拥有”VecVec 将在函数退出时被销毁)。例如,我们可以从Vec 中删除我们想要返回的String,这样Vec 就不再拥有那个String

    fn get_a_word(mut list: Vec<String>, minLength: uint, maxLength: uint) -> String {
        loop {
            let idx = rand::random::<uint>() % list.len();
            if list[idx].len() > minLength && list[idx].len() < maxLength {
                return list.remove(idx).unwrap();
            }
        }
    }
    

    如果您不想在get_a_word 退出时销毁Vec,那么该函数应该接收一个借用的指向Vec 的指针。如果我们这样做,函数可以简单地返回一个字符串切片。

    fn get_a_word(list: &Vec<String>, minLength: uint, maxLength: uint) -> &str {
        loop {
            let idx = rand::random::<uint>() % list.len();
            if list[idx].len() > minLength && list[idx].len() < maxLength {
                return list[idx].as_slice();
            }
        }
    }
    

    如果您必须绝对返回 String,那么您可以克隆该值:

    fn get_a_word(list: &Vec<String>, minLength: uint, maxLength: uint) -> String {
        loop {
            let idx = rand::random::<uint>() % list.len();
            if list[idx].len() > minLength && list[idx].len() < maxLength {
                 return list[idx].clone();
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-07-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多