简体   繁体   中英

storing the return value from an Fn closure

The code below works if &dyn Fn(&mut [u8]) is changed to &dyn FnOnce(&mut [u8]) , because then f can be moved safely. However, I really can't make it FnOnce because further I find some problems. Fn would work.

However, I really need to capture the result r and return it in consume , like in below

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()
    }
}

I know that making it Box<dyn FnOnce(&mut [u8]) would work but I'm trying to avoid dynamic allocation.

Is there a way to make this work?

There are two changes needed to make this compile. One is to change F: FnOnce(&mut [u8])... in the consume() function definition to F: Fn(&mut [u8])... An FnOnce()-type closure will consume itself when called, so it can only be called once.

Changing this will give another error that r cannot be assigned to inside the closure. This is because r is a capture variable from outside the closure, and the Fn() type will borrow captured variables immutably. By changing the second Fn() to FnMut(), the r variable will be captured as a mutable reference, and can therefore be assigned to from inside the closure:

Arc<dyn Fn(&dyn FnMut(&mut [u8]) , usize) -> Result<(), ()> + Send + Sync>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM