如果将
&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])
会起作用,但我试图避免动态分配。
有办法让这个工作吗?
编译需要进行两处更改。一是把
F: FnOnce(&mut [u8])...
函数定义中的consume()
改为F: Fn(&mut [u8])...
FnOnce() 类型的闭包在调用时会消耗自身,因此只能调用一次。
更改此设置会产生另一个错误,无法将
r
分配给闭包内部。这是因为 r
是来自闭包外部的捕获变量,并且 Fn() 类型将不可变地借用捕获的变量。通过将第二个 Fn() 更改为 FnMut(),r
变量将被捕获为可变引用,因此可以从闭包内部分配给:
Arc<dyn Fn(&dyn FnMut(&mut [u8]) , usize) -> Result<(), ()> + Send + Sync>
use std::sync::Arc;
pub type OnVirtualTunWrite =
Arc<dyn Fn(&dyn FnMut(&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: Fn(&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()
}
}
Fn
以参考形式带来捕获的值。与T
FnMut
获取捕获的值作为可修改的参考。 &mutT
FnOnce
按原样获取捕获的值。 T