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

fas*_*cen 10 rust

我开始学习Rust,我试图实现一个函数来反转字符串向量.我找到了一个解决方案,但我不明白为什么它有效.

这有效:

fn reverse_strings(strings:Vec<&str>) -> Vec<&str> {
  let actual: Vec<_> = strings.iter().cloned().rev().collect();
  return actual;
}
Run Code Online (Sandbox Code Playgroud)

但事实并非如此.

fn reverse_strings(strings:Vec<&str>) -> Vec<&str> {
  let actual: Vec<_> = strings.iter().rev().collect(); // without clone
  return actual;
}
Run Code Online (Sandbox Code Playgroud)

错误信息

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]
Run Code Online (Sandbox Code Playgroud)

有人能解释一下为什么吗?第二个功能会发生什么?谢谢!

Jor*_*eña 17

所以调用.cloned()就像.map(|i| i.clone())在同一个位置做的那样(即你可以用后者替换前者).

问题在于,当您调用时iter(),您正在迭代/操作对正在迭代的项的引用.请注意,向量已经包含'references',特别是字符串切片.

因此,为了放大一点,让我们cloned()map()上面提到的等效物替换,用于教学目的,因为它们是等价的.这实际上是这样的:

.map(|i: & &str| i.clone())
Run Code Online (Sandbox Code Playgroud)

所以请注意,这是对引用(切片)的引用,因为就像我说的那样,iter()对项目的引用进行操作,而不是项目本身.因此,由于迭代的向量中的单个元素是类型&str,所以我们实际上得到了对它的引用,即& &str.通过调用clone()这些项目,我们从a & &str到a &str,就像调用.clone()a &i64会导致一个i64.

因此,要将所有内容组合在一起,请iter()迭代对元素的引用.所以如果你从你构造的迭代器(你通过调用构造的iter())产生的收集项中创建一个新的向量,你将得到一个引用的引用向量,即:

let actual: Vec<& &str> = strings.iter().rev().collect();
Run Code Online (Sandbox Code Playgroud)

所以首先认识到这是一样的类型你说的函数返回时,Vec<&str>.但更重要的是,这些引用的生命周期对于函数是本地的,因此即使您将返回类型更改为Vec<& &str>您也会获得生命周期错误.

但是,你可以做的其他事情就是使用这种into_iter()方法.这种方法实际上迭代每个元素,而不是对它的引用.然而,这意味着该元件被移动从原始迭代器/容器中.这只能在您的情况下实现,因为您按值传递矢量,因此您可以将元素移出它.

fn reverse_strings(strings:Vec<&str>) -> Vec<&str> {
  let actual: Vec<_> = strings.into_iter().rev().collect();
  return actual;
}
Run Code Online (Sandbox Code Playgroud)

围栏

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