`Vec<&str>` 类型的值无法从 `std::iter::Iterator<Item=&&str>` 构建

con*_*son 4 rust

为什么这段代码可以正常工作

fn main() {
let v1 = vec!["lemonade", "lemon", "type", "lid"];
println!("{:?}", v1.iter().filter(|item| item.starts_with("l")).collect::<Vec<_>>());
}
Run Code Online (Sandbox Code Playgroud)

虽然这段代码给我带来了一个错误,但我有点明白为什么这不起作用并且我知道如何修复它,但我真的不明白它返回什么类型,所以我可以将“_”替换为不那个通用的

fn main() {
let v1 = vec!["lemonade", "lemon", "type", "lid"];
println!("{:?}", v1.iter().filter(|item| item.starts_with("l")).collect::<Vec<&str>>());
}
Run Code Online (Sandbox Code Playgroud)

错误

error[E0277]: a value of type `Vec<&str>` cannot be built from an iterator over elements of 
type `&&str`
--> src\main.rs:3:69
 |
 3    |     println!("{:?}", v1.iter().filter(|item| item.starts_with("l")).collect:: 
 <Vec<&str>>());
 |                                                                     ^^^^^^^ value of type 
 `Vec<&str>` cannot be built from `std::iter::Iterator<Item=&&str>`
 |
 = help: the trait `FromIterator<&&str>` is not implemented for `Vec<&str>`
 = help: the trait `FromIterator<T>` is implemented for `Vec<T>`
 note: required by a bound in `collect`
--> C:\Users\Mululi\.rustup\toolchains\stable-x86_64-pc-windows- 
 msvc\lib/rustlib/src/rust\library\core\src\iter\traits\iterator.rs:1788:19
 |
 1788 |     fn collect<B: FromIterator<Self::Item>>(self) -> B
 |                   ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect`
Run Code Online (Sandbox Code Playgroud)

我无法完全理解编译器的意思

Joh*_*ica 6

解释错误

让我们详细看看这些类型。需要一些文档引用才能弄清真相,所以请耐心等待。

let v1 = vec!["lemonade", "lemon", "type", "lid"];
Run Code Online (Sandbox Code Playgroud)

v1是一个Vec<&str>.

v1.iter()
Run Code Online (Sandbox Code Playgroud)

Vec没有iter方法,但它实现了Deref<Target = [T]> 以下功能

pub fn iter(&self) -> Iter<'_, T>
Run Code Online (Sandbox Code Playgroud)

Iter这是一个名为 的结构std::slice::Iter。它是什么样的迭代器?我们需要看一下它的Iterator实现

impl<'a, T> Iterator for Iter<'a, T> {
    type Item = &'a T;
}
Run Code Online (Sandbox Code Playgroud)

这告诉我们迭代器产生类型为 的项&T。请记住,我们有一个Vec<&str>, 所以T = &str。这意味着我们真正拥有的是一个Iterator<Item = &&str>. 这就是您收到的错误的根源。

修复

那么,我们如何获得 anIterator<Item = &str>而不是 an呢Iterator<Item = &&str>?有多种方法,包括:

1.into_iterator()

使用Vec其中的实现IntoIteratorItem = Tinto_iterator()产生Ts 而不是&Ts。

v1.into_iter().filter(...)
Run Code Online (Sandbox Code Playgroud)

这是有效的,但请注意它会消耗向量。它不会返回引用项目的迭代器,它实际上将项目从向量移出并移入使用代码。调用后该向量无法使用into_iter

2.iter().copied()

如果T: Copy您可以调用copied将 an 转换Iterator<Item = &T>Iterator<Item = T>.

v1.iter().copied().filter(...)
Run Code Online (Sandbox Code Playgroud)

这项技术很棒,因为它不消耗向量,而且它会起作用,因为&str确实Copy。所有参考文献均Copy归功于此一揽子实施

impl<T: ?Sized> Copy for &T {}
Run Code Online (Sandbox Code Playgroud)

3.iter().cloned()

如果T: Clone您可以调用cloned克隆所有项目并将 an 转换Iterator<Item = &T>Iterator<Item = T>.

v1.iter().cloned().filter(...)
Run Code Online (Sandbox Code Playgroud)

任何东西都是CopyClone所以你确实可以克隆&str引用。