为什么cloned()允许这个函数编译

时间:2015-07-04 06:09:55

标签: rust

我开始学习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]

有人可以向我解释原因吗?第二个功能会发生什么?谢谢!

1 个答案:

答案 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()

playpen

这可能比克隆更有意义,因为我们通过值传递向量,我们被允许对元素做任何事情,包括将它们移动到不同的位置(在这种情况下是新的反向向量) 。 即使我们不这样做,矢量也会在该函数的末尾被删除,所以我们不妨。如果我们不允许克隆,那么克隆会更合适(例如,如果我们通过引用传递矢量,或者更可能传递切片而不是矢量)。