如果&dyn Fn(&mut [u8])
更改为&dyn FnOnce(&mut [u8])
,则下面的代码有效,因为这样f
就可以安全地移动。然而,我真的不能把它变成FnOnce
,因为我发现了一些问题。Fn
会起作用。
然而,我确实需要捕获结果r
,并在consume
中返回它,就像下面的一样
use std::sync::Arc;
pub type OnVirtualTunWrite = Arc<dyn Fn(&dyn Fn(&mut [u8]) , usize) -> Result<(), ()> + Send + Sync>;
struct A {
on_virtual_tun_write: OnVirtualTunWrite
}
impl A {
fn consume<R, F>(self, len: usize, f: F) -> Result<R,()>
where
F: FnOnce(&mut [u8]) -> Result<R,()>,
{
let mut r: Option<Result<R,()>> = None;
let result = (self.on_virtual_tun_write)(&|b: &mut [u8]| {
r = Some(f(b));
}, len);
r.unwrap()
}
}
我知道让它成为Box<dyn FnOnce(&mut [u8])
是可行的,但我正在努力避免动态分配。
有没有办法做到这一点?
编译需要两个更改。一种是将consume()
函数定义中的F: FnOnce(&mut [u8])...
更改为F: Fn(&mut [u8])...
FnOn((类型的闭包在调用时会消耗自身,因此只能调用一次。
更改此项将导致另一个错误,r
无法在闭包内分配。这是因为r
是一个来自闭包外部的捕获变量,Fn((类型将不可变地借用捕获的变量。通过将第二个Fn((更改为FnMut((,r
变量将被捕获为可变引用,因此可以从闭包内部分配给:
Arc<dyn Fn(&dyn FnMut(&mut [u8]) , usize) -> Result<(), ()> + Send + Sync>