2014-11-24 39 views
1

我和防锈现在尝试“不能搬出取消引用'&'终场前的”,而我变得非常绊倒通过各种随机编译器错误的像这样的:与向量

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

有关的代码片段转载如下。列表是一个单词列表,其思想是从列表中返回一个随机单词,该单词在一定长度内(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<T> retvals,不试图获取值从集合中。

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

回答

2

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

由于函数接收Vec的价值,这意味着Vec移入功能,因此该功能可以做任何我们想做的事情,因为它NOW的“拥有” Vec(该Vec时就会破坏该函数退出)。例如,我们可以从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(); 
     } 
    } 
} 

如果您并不意味着有Vec破坏时get_a_word退出,那么函数应该接受借来的指针,而不是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(); 
     } 
    } 
} 
+0

真棒解释,非常感谢! – nameless912 2014-11-24 04:41:20

3

只有一件事情可以自己在一个时间一个对象,你要在那里做什么会打破这个不变性,因为你会在矢量和返回位置都返回字符串。 list[idx]扩展的方法Index::index或多或少地*list.index(idx)(事实上它比这要复杂,因为是否应该Index::indexIndexMut::index_mut基于上下文确定,&list[idx]将只是一个&self -taking methodlist.index(idx)list[idx].method()将是list.index(idx).method())。

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

  • 从列表中删除该值,并返回它。你所拥有的Vec<String>的其余部分将被删除,因此除了正确的之外,所有的String都将被释放。

    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(); 
         } 
        } 
    } 
    
+0

你怎么能(快速)告诉'list [idx]'展开为'* list.index [&idx]'?虽然我同意它这样做是有道理的,但我找不到这方面的文档。事实上,您发布的文档中的函数定义,'fn index(&'a self,index:Idx) - >&'a Self :: Output',似乎并不要求'index'是一个参考。 – mSSM 2015-09-03 13:12:50

+0

@mSSM:自那时起,通过引用按值来引用索引。现在,'list [index]'等同于'* list.index(index)'或'list.index(index)'或'list.index_mut(index)',这取决于它的使用方式。 '&list [index]'是规范形式,意思是'list.index(index)',因此'list [index]'是'* list.index(index)'是有意义的。它也受到自动对照规则的约束,所以'list [index] .method_that_takes_self_by_ref()'相当于'(&list [index])。method_that_takes_self_by_ref()'。 – 2015-09-03 20:52:06