为什么这段代码可以正常工作
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)
我无法完全理解编译器的意思
让我们详细看看这些类型。需要一些文档引用才能弄清真相,所以请耐心等待。
Run Code Online (Sandbox Code Playgroud)let v1 = vec!["lemonade", "lemon", "type", "lid"];
v1是一个Vec<&str>.
Run Code Online (Sandbox Code Playgroud)v1.iter()
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>?有多种方法,包括:
into_iterator()使用Vec其中的实现IntoIteratorItem = T。into_iterator()产生Ts 而不是&Ts。
v1.into_iter().filter(...)
Run Code Online (Sandbox Code Playgroud)
这是有效的,但请注意它会消耗向量。它不会返回引用项目的迭代器,它实际上将项目从向量移出并移入使用代码。调用后该向量无法使用into_iter。
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)
iter().cloned()如果T: Clone您可以调用cloned克隆所有项目并将 an 转换Iterator<Item = &T>为Iterator<Item = T>.
v1.iter().cloned().filter(...)
Run Code Online (Sandbox Code Playgroud)
任何东西都是Copy,Clone所以你确实可以克隆&str引用。