Reputation: 125
I think these two methods are equivalent, but there is an error. What is the reason? Is there a better way to express it?
pub fn create_pair() -> () {
let vec_num = vec![1, 2, 3];
let vec_num2 = &vec_num;
let all = &vec_num
.iter()
.flat_map(move |a| vec_num2.iter().map(move |b| [a, b]))
.collect::<Vec<_>>();
println!("{:?}", all);
}
[[1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [3, 1], [3, 2], [3, 3]]
pub fn create_pair() -> () {
let vec_num = vec![1, 2, 3];
let all = &vec_num
.iter()
.flat_map(move |a| &vec_num.iter().map(move |b| [a, b]))
.collect::<Vec<_>>();
println!("{:?}", all);
}
error[E0277]: `&std::iter::Map<std::slice::Iter<'_, {integer}>, [closure@src/main.rs:5:48: 5:63 a:_]>` is not an iterator
--> src/main.rs:5:10
|
5 | .flat_map(move |a| &vec_num.iter().map(move |b| [a, b]))
| ^^^^^^^^ `&std::iter::Map<std::slice::Iter<'_, {integer}>, [closure@src/main.rs:5:48: 5:63 a:_]>` is not an iterator
|
= help: the trait `std::iter::Iterator` is not implemented for `&std::iter::Map<std::slice::Iter<'_, {integer}>, [closure@src/main.rs:5:48: 5:63 a:_]>`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&std::iter::Map<std::slice::Iter<'_, {integer}>, [closure@src/main.rs:5:48: 5:63 a:_]>`
error[E0599]: no method named `collect` found for struct `std::iter::FlatMap<std::slice::Iter<'_, {integer}>, &std::iter::Map<std::slice::Iter<'_, {integer}>, [closure@src/main.rs:5:48: 5:63 a:_]>, [closure@src/main.rs:5:19: 5:64 vec_num:_]>` in the current scope
--> src/main.rs:6:10
|
6 | .collect::<Vec<_>>();
| ^^^^^^^ method not found in `std::iter::FlatMap<std::slice::Iter<'_, {integer}>, &std::iter::Map<std::slice::Iter<'_, {integer}>, [closure@src/main.rs:5:48: 5:63 a:_]>, [closure@src/main.rs:5:19: 5:64 vec_num:_]>`
|
= note: the method `collect` exists but the following trait bounds were not satisfied:
`&std::iter::Map<std::slice::Iter<'_, {integer}>, [closure@src/main.rs:5:48: 5:63 a:_]>: std::iter::IntoIterator`
which is required by `std::iter::FlatMap<std::slice::Iter<'_, {integer}>, &std::iter::Map<std::slice::Iter<'_, {integer}>, [closure@src/main.rs:5:48: 5:63 a:_]>, [closure@src/main.rs:5:19: 5:64 vec_num:_]>: std::iter::Iterator`
`std::iter::FlatMap<std::slice::Iter<'_, {integer}>, &std::iter::Map<std::slice::Iter<'_, {integer}>, [closure@src/main.rs:5:48: 5:63 a:_]>, [closure@src/main.rs:5:19: 5:64 vec_num:_]>: std::iter::Iterator`
which is required by `&mut std::iter::FlatMap<std::slice::Iter<'_, {integer}>, &std::iter::Map<std::slice::Iter<'_, {integer}>, [closure@src/main.rs:5:48: 5:63 a:_]>, [closure@src/main.rs:5:19: 5:64 vec_num:_]>: std::iter::Iterator`
Upvotes: 1
Views: 562
Reputation: 30587
According to the Rust reference, the &
operator has a lower precedence than a method call. So this closure:
move |a| &vec_num.iter().map(move |b| [a, b])
would be first trying to calculate vec_num.iter().map(move |b| [a, b])
, and then take a reference to that result, and return it. That is not at all equivalent to your first sample.
I have a hunch that you meant this instead:
move |a| (&vec_num).iter().map(move |b| [a, b])
That does not work either, but for completely different reasons:
error: captured variable cannot escape `FnMut` closure body
--> src/main.rs:17:28
|
14 | let vec_num = vec![1, 2, 3];
| ------- variable defined here
...
17 | .flat_map(move |a| (&vec_num).iter().map(move |b| [a, b]))
| - ^^-------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| | | |
| | | variable captured here
| | returns a reference to a captured variable which escapes the closure body
| inferred to be a `FnMut` closure
|
= note: `FnMut` closures only have access to their captured variables while they are executing...
= note: ...therefore, they cannot allow references to captured variables to escape
error[E0505]: cannot move out of `vec_num` because it is borrowed
--> src/main.rs:17:19
|
15 | let all = &vec_num
| ------- borrow of `vec_num` occurs here
16 | .iter()
17 | .flat_map(move |a| (&vec_num).iter().map(move |b| [a, b]))
| -------- ^^^^^^^^ ------- move occurs due to use in closure
| | |
| | move out of `vec_num` occurs here
| borrow later used by call
error: aborting due to 2 previous errors
You can't both borrow vec_num
for a method call, at the same time as moving it into the closure. And, since the closure now owns vec_num
, you can't return a value that ultimately contains a reference to vec_num
, because it would be dropped as soon as you returned from the closure.
If you take away the move
, then the closure will borrow vec_num
instead of consuming it.
Again, according to the Rust Reference:
Closures can capture variables:
- by reference: &T
- by mutable reference: &mut T
- by value: T
They preferentially capture variables by reference and only go lower when required.
You don't need a &
to indicate that variables should be captured by reference. This works:
pub fn main() -> () {
let vec_num = vec![1, 2, 3];
let all = &vec_num
.iter()
.flat_map(|a| vec_num.iter().map(move |b| [a, b]))
.collect::<Vec<_>>();
println!("{:?}", all);
}
Upvotes: 2