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| {
()
})
}
这不能编译,因为
.and_then(move |b| {
^^^^^^^^^ cannot move out of captured outer variable in an `FnMut` closure
我对错误的理解是:
FnMut
,它通过获取其所有权来捕获notificator
send
再次需要获得所有权send
和闭包B都在修改notificator
,因此出现了错误。我的理解对吗?我该如何解决这个问题?
发布于 2018-10-29 01:25:48
嵌套闭包是很棘手的。
考虑到这一点:
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
)。
外部闭包被多次调用,每次使用一个新字符串,每次创建捕获该字符串的新内部闭包。
但是如果你想捕捉的东西来自更远的地方呢?
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_then
和for_each
调用最终会出现在这段代码中。但只有一个人可以通过移动来捕捉。
因此,要解决这个问题,要么需要确保只有一个闭包B,要么需要确保每个人都有足够的mpsc::Sender
。
第一种方法是将闭包从嵌套上下文中提取出来。
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面临着同样的问题,所以您必须多次这样做:
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
,同时也尝试使用它。
https://stackoverflow.com/questions/53038935
复制相似问题