我开始学习Rust,我试图实现一个函数来反转字符串向量。我找到了解决方案,但我不明白为什么会有效。
这有效:
fn reverse_strings(strings:Vec<&str>) -> Vec<&str> {
let actual: Vec<_> = strings.iter().cloned().rev().collect();
return actual;
}
但这不是。
fn reverse_strings(strings:Vec<&str>) -> Vec<&str> {
let actual: Vec<_> = strings.iter().rev().collect(); // without clone
return actual;
}
错误消息
src/main.rs:28:10: 28:16 error: mismatched types:
expected `collections::vec::Vec<&str>`,
found `collections::vec::Vec<&&str>`
(expected str,
found &-ptr) [E0308]
有人可以向我解释原因吗?第二个功能会发生什么?谢谢!
答案 0 :(得分:16)
因此,对.cloned()
的调用基本上就像在同一位置执行.map(|i| i.clone())
一样(即您可以用后者替换前者)。
问题在于,当您调用iter()
时,您正在迭代/操作引用到正在迭代的项目。请注意,向量已经包含'references',特别是字符串切片。
为了放大一点,让我们用上面提到的等效cloned()
替换map()
用于教学目的,因为它们是等价的。这就是它的实际情况:
.map(|i: & &str| i.clone())
请注意,这是对引用(切片)的引用,因为就像我说的那样,iter()
对项目的引用进行操作,而不是项目本身。因此,由于迭代的向量中的单个元素是&str
类型,因此我们实际上得到引用,即& &str
。通过在每个项目上调用clone()
,我们从& &str
转到&str
,就像在.clone()
上调用&i64
会导致{ {1}}。
因此,为了将所有内容组合在一起,i64
将引用迭代到元素。因此,如果您从您构造的迭代器(通过调用iter()
构造的)生成的收集项中创建一个新向量,您将获得引用的向量,即:< / p>
iter()
首先要意识到, 与你所说的函数返回的类型let actual: Vec<& &str> = strings.iter().rev().collect();
相同。但更重要的是,这些引用的生命周期对于函数是本地的,因此即使将返回类型更改为Vec<&str>
,也会出现生命周期错误。
然而,您可以做的其他事情是使用Vec<& &str>
方法。这个方法实际上 迭代每个元素,而不是对它的引用。但是,这意味着元素是从原始迭代器/容器移动。这只适用于您的情况,因为您按值传递矢量,因此您可以将元素移出它。
into_iter()
这可能比克隆更有意义,因为我们通过值传递向量,我们被允许对元素做任何事情,包括将它们移动到不同的位置(在这种情况下是新的反向向量) 。 和 即使我们不这样做,矢量也会在该函数的末尾被删除,所以我们不妨。如果我们不允许克隆,那么克隆会更合适(例如,如果我们通过引用传递矢量,或者更可能传递切片而不是矢量)。