Reputation: 1009
Below is an reduced example from my code that reads a directory, traverses over the files, and appends a comment to the end of each file...
This example shows a Vec<Option<bool>>
that after calling iter()
the compiler is interpreting the Option<_>
as a borrow &Option<_>
type. I'd like to understand why I'm seeing this behavior.
fn main() {
let vec = vec![Some(true), None];
vec.iter()
.filter_map(|o| o)
.count();
}
Compiler output
src/main.rs:50:25: 50:26 error: mismatched types:
expected `core::option::Option<_>`,
found `&core::option::Option<bool>`
(expected enum `core::option::Option`,
found &-ptr) [E0308]
src/main.rs:50 .filter_map(|o| o)
Upvotes: 4
Views: 477
Reputation: 86306
How about this:
fn main() {
let my_vec = vec![Some(true), None];
println!("{}", my_vec.iter().filter_map(|&x| x).count());
}
When apply filter_map
, you can map &x
to x
, and your code will work.
As @Shepmaster pointed out in the comment this is only possible for types that implement Copy
.
Upvotes: 1
Reputation: 431919
Vec::iter
returns an Iter
struct, which implements Iterator
as:
impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a T;
}
Said another way, the type of the value returned from each call to Iterator::next
will be a reference to the item in the vector.
If you change to vec.into_iter()
, your code works:
fn main() {
let vec = vec![Some(true), None];
vec.into_iter()
.filter_map(|o| o)
.count();
}
In this case, you are iterating on an IntoIter
struct which implements Iterator
differently, returning the object itself:
impl<T> Iterator for IntoIter<T> {
type Item = T;
}
This is required because only one thing may own each vector item at a time. Generally, you want to let the vector own the item and operate on references. into_iter
consumes the vector, transferring ownership of the entire vector to the IntoIter
struct. That struct is then allowed to give ownership of each item to the filter_map
call.
If your type implements Clone
, you could also clone each item. This allows the vector to maintain ownership and creates a new item:
fn main() {
let vec = vec![Some(true), None];
vec.iter()
.cloned()
.filter_map(|o| o)
.count();
}
Upvotes: 4