我现在正在尝试使用Rust,而且我真的被各种各样的随机编译器错误所困扰:
error: cannot move out of dereference of `&`-pointer
return list[idx];
^~~~~~~~~
有问题的片段转载如下。 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<T>
次撤消时,这种情况就会出现,而不是试图从集合中获取价值。< / p>
这可能是一个非常简单的问题,但为什么地球上没有Rust只让你从集合/矢量/数组中返回一个值?
答案 0 :(得分:3)
一次只能有一件东西可以拥有一个对象,而你在那里尝试做的事情会破坏那个不变量,因为你将在向量和返回位置返回字符串。对于方法Index::index
,list[idx]
或多或少地扩展到*list.index(idx)
(事实上,它比Index::index
或IndexMut::index_mut
更复杂一点。根据上下文确定,&list[idx]
只是list.index(idx)
的{{1}}和list[idx].method()
的{{1}} - &self
将是method
。< / p>
你有几个选择;这里有三个:
从列表中删除该值,并将其返回。你所拥有的list.index(idx).method()
的其余部分将被删除,因此除了正确的Vec<String>
之外的所有String
最终都将被释放。
return list.swap_remove(idx).unwrap();
(比较swap_remove
和remove
,前者更有效但改变了在这种情况下完全正常的顺序)代替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();
}
}
}
答案 1 :(得分:2)
list[idx]
是*list.index(&idx)
的简写。 index()
在被索引的值内返回一个借来的指针(这里是Vec
)。您不能通过取消引用借来的指针来移动值(此处为String
);这就像拥有字符串的String
中的“{1}}”。 Vec
拥有堆上的分配;我们不能有两个引用相同堆分配的String
值,或者它们都会在删除时尝试释放它,这将导致双重释放。
由于函数通过值接收String
,这意味着Vec
被移入函数中,因此函数可以随心所欲地执行它,因为它“拥有”{ {1}}(当函数退出时,Vec
将被销毁)。例如,我们可以删除我们要从Vec
返回的Vec
,以便String
不再拥有该Vec
的所有权。
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();
}
}
}