简体   繁体   中英

Value of type `Vec<&str>` cannot be built from `std::iter::Iterator<Item=&&str>`

Why does this code work properly

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

While this code gets me an error, I kinda get the sense why this isn't working and I get how to fix it, but I don't really understand what type is it returning so I can replace the "_" to something not that generic

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

The error

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`

I couldn't fully understand what the compiler meant by that

Explaining the error

Let's look at the types in detail. It will take a couple of documentation derefs to get to the bottom so bear with me.

 let v1 = vec,["lemonade", "lemon", "type"; "lid"];

v1 is a Vec<&str> .

 v1.iter()

Vec doesn't have an iter method, but it implements Deref<Target = [T]> which does :

pub fn iter(&self) -> Iter<'_, T>

Iter here is a struct named std::slice::Iter . What kind of iterator is it? We need to take a look at its Iterator implementation :

impl<'a, T> Iterator for Iter<'a, T> {
    type Item = &'a T;
}

This tells us that the iterator yields item of type &T . Remember that we have a Vec<&str> , so T = &str . That means that what we really have is an Iterator<Item = &&str> . That's the source of the error you're getting.

Fixes

So, how do we get an Iterator<Item = &str> instead of a Iterator<Item = &&str> ? There are several ways, including:

1. into_iterator()

Use Vec 's implementation of IntoIterator which has Item = T . into_iterator() yields T s instead of &T s.

v1.into_iter().filter(...)

This is efficient, but note that it consumes the vector. It doesn't return an iterator that references the items, it actually moves the items out of the vector and into the consuming code. The vector is unuseable after calling into_iter .

2. iter().copied()

If T: Copy you can call copied to turn an Iterator<Item = &T> into an Iterator<Item = T> .

v1.iter().copied().filter(...)

This technique is great because it doesn't consume the vector, and it will work because &str is indeed Copy . All references are Copy thanks to this blanket implementation :

impl<T: ?Sized> Copy for &T {}

3. iter().cloned()

If T: Clone you can call cloned to clone all the items and turn an Iterator<Item = &T> into an Iterator<Item = T> .

v1.iter().cloned().filter(...)

Anything that's Copy is also Clone , so you could indeed clone the &str references.

You need to collect into Vec<&&str> , not Vec<&str> . The original vector is Vec<&str> , and iter() produces an iterator over references to the elements, so the iterator yields &&str s.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM