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| {
()
})
}
Run Code Online (Sandbox Code Playgroud)
这不会编译,因为
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| {
()
})
}
Run Code Online (Sandbox Code Playgroud)
我对错误的理解是:
FnMut,它notificator通过获取其所有权来捕获send再次需要取得所有权send和 Closure B 都在修改notificator错误。我的理解对吗?我怎么解决这个问题?
嵌套闭包很棘手。
考虑一下:
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());
});
}
Run Code Online (Sandbox Code Playgroud)
请注意,内部闭包a通过移动捕获。这可以。外部闭包拥有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
});
});
}
Run Code Online (Sandbox Code Playgroud)
然后你会看到你看到的错误(除了Fnvs FnMut,这对问题无关紧要)。每次调用外部闭包时都会重新创建内部闭包(它必须如此,因为它a每次都必须捕获),但它outer_s每次都尝试通过移动来捕获。这是行不通的;第一次后,outer_s被移出并因此无效。
要将其映射回您的代码,说“闭包 B 捕获notificator”是错误的,因为不只有一个闭包 B。有多少是必要的,但通常您的嵌套and_then和for_each调用最终会出现在那段代码中。但只有一个人可以通过移动来捕捉。
所以要解决这个问题,你要么需要确保只有一个闭包 B,要么确保mpsc::Sender每个人都有足够的s。
第一种方法是将闭包从嵌套上下文中拉出来。
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| {
()
})
Run Code Online (Sandbox Code Playgroud)
除了这行不通,因为现在 Closure 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| {
()
})
Run Code Online (Sandbox Code Playgroud)
第二种方式涉及大量clone()调用,由于我无法对您的代码进行类型检查,因此我不会尝试编写它。
然而,当一切都说完了,你的代码仍然会失败,因为你在Proxy尝试使用它的同时也会离开。