首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么这个迭代器不能用作flat_map闭包的返回值?

为什么这个迭代器不能用作flat_map闭包的返回值?
EN

Stack Overflow用户
提问于 2020-09-29 09:13:11
回答 1查看 137关注 0票数 1

我认为这两种方法是等价的,但有一个错误。原因何在?有没有更好的表达方式?

代码语言:javascript
复制
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);
}
代码语言:javascript
复制
[[1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [3, 1], [3, 2], [3, 3]]
代码语言:javascript
复制
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);
}
代码语言:javascript
复制
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`
EN

回答 1

Stack Overflow用户

发布于 2020-09-29 10:25:43

根据Rust reference&操作符的优先级低于方法调用。所以这个闭包:

代码语言:javascript
复制
move |a| &vec_num.iter().map(move |b| [a, b])

将首先尝试计算vec_num.iter().map(move |b| [a, b]),然后引用该结果并返回它。这根本不等同于你的第一个样本。

我有预感你的意思是:

代码语言:javascript
复制
move |a| (&vec_num).iter().map(move |b| [a, b])

这也不起作用,但原因完全不同:

代码语言:javascript
复制
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

您不能在将方法调用移到闭包中的同时,同时借用vec_num进行方法调用。而且,由于闭包现在拥有vec_num,所以不能返回最终包含对vec_num的引用的值,因为一旦从闭包返回,它就会被删除。

如果您移除了move,那么闭包将借用vec_num而不是消耗它。

同样,根据Rust参考:

闭包可以捕获变量:

  • by reference:&T
  • by mutable:&mut T
  • by value: T

它们优先通过引用捕获变量,只有在需要时才会降低。

您不需要&来指示应该通过引用捕获变量。这是可行的:

代码语言:javascript
复制
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);
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64111547

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档