首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >无法在“FnMut`闭包”中移出捕获的变量

无法在“FnMut`闭包”中移出捕获的变量
EN

Stack Overflow用户
提问于 2018-10-28 20:53:13
回答 1查看 10.2K关注 0票数 8
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
pub fn create_future(
    notificator: mpsc::Sender<usize>,
    proxy: Proxy,
) -> impl Future<Item = (), Error = ()> {
    proxy.something()
        .and_then(move |sub| {
            sub.for_each(move |a| { // <---- Closure A
                proxy.something_else(a)
                    .and_then(move |b| { // <---- Closure B
                        notificator.send(b.len());  // <---- Error!
                        Ok(())
                    })
                    .or_else(|e| {
                        panic!("oops {}", e);
                        Ok(())
                    })
            })
        })
        .map_err(|e| {
            ()
        })
}

这不能编译,因为

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.and_then(move |b| {
          ^^^^^^^^^ cannot move out of captured outer variable in an `FnMut` closure

我对错误的理解是:

  1. 闭包B是FnMut,它通过获取其所有权来捕获notificator
  2. 在闭包B中,send再次需要获得所有权
  3. 现在,send和闭包B都在修改notificator,因此出现了错误。

我的理解对吗?我该如何解决这个问题?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-10-29 01:25:48

嵌套闭包是很棘手的。

考虑到这一点:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
fn use_a_fn_multiple_times(f: impl Fn(String)) {
    f("foo".to_owned());
    f("bar".to_owned());
}

fn use_fn_once(f: impl FnOnce() -> Vec<u8>) {
    println!("Bytes: {:?}", f());
}

fn main() {
  use_a_fn_multiple_times(|a: String| {
    use_fn_once(move || a.into_bytes());
  });
}

游乐场

注意,内部闭包通过移动捕获a。这很好。外部闭包拥有a,可以使用它做它想做的事情,包括将它移动到内部闭包中(因为它消耗了捕获的值,所以它是一个FnOnce)。

外部闭包被多次调用,每次使用一个新字符串,每次创建捕获该字符串的新内部闭包。

但是如果你想捕捉的东西来自更远的地方呢?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
fn use_a_fn_multiple_times(f: impl Fn(String)) {
    f("foo".to_owned());
    f("bar".to_owned());
}

fn use_fn_once(f: impl FnOnce() -> Vec<u8>) {
    println!("Bytes: {:?}", f());
}

fn main() {
  let outer_s = "see:".to_owned();

  use_a_fn_multiple_times(|a: String| {
    use_fn_once(move || {
        let mut v = outer_s.into_bytes();
        v.extend(a.into_bytes());
        v
    });
  });
}

游乐场

然后得到所看到的错误(除了Fn vs FnMut,这对问题不重要)。内部闭包是在每次调用外部闭包时重新创建的(必须是,因为每次都必须捕获a ),但它每次都试图通过移动来捕获outer_s。这不能工作;第一次之后,outer_s被移出,因此无效。

为了将其映射回您的代码,说“闭包B捕获notificator”是错误的,因为不只是一个闭包B。有很多必要的闭包,不管嵌套的and_thenfor_each调用最终会出现在这段代码中。但只有一个人可以通过移动来捕捉。

因此,要解决这个问题,要么需要确保只有一个闭包B,要么需要确保每个人都有足够的mpsc::Sender

第一种方法是将闭包从嵌套上下文中提取出来。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let closure_b = move |b| {
    notificator.send(b.len());
    Ok(())
};
proxy.something()
    .and_then(move |sub| {
        sub.for_each(move |a| { // <---- Closure A
            proxy.something_else(a)
                .and_then(closure_b)
                .or_else(|e| {
                    panic!("oops {}", e);
                    Ok(())
                })
        })
    })
    .map_err(|e| {
        ()
    })

但这是行不通的,因为现在闭包A面临着同样的问题,所以您必须多次这样做:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let closure_b = move |b| {
    notificator.send(b.len());
    Ok(())
};
let closure_a = move |a| {
    proxy.something_else(a)
        .and_then(closure_b)
        .or_else(|e| {
            panic!("oops {}", e);
            Ok(())
        })
};
proxy.something()
    .and_then(move |sub| {
        sub.for_each(closure_a)
    })
    .map_err(|e| {
        ()
    })

第二种方法涉及大量的clone()调用,由于我无法键入-检查您的代码,所以我不会尝试编写它。

但是,当所有这些都说完之后,您的代码仍然会失败,因为您正在离开Proxy,同时也尝试使用它。

票数 14
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53038935

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文