简体   繁体   中英

Storing the return type of function called inside closure

I'm trying to store the result of a function call in r . However, I get that the type R may not live long enough

use std::sync::Arc;

pub type OnVirtualTunWrite = Arc<dyn Fn(Box<dyn FnOnce(&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 r: Result<R,()>;
        let result = (self.on_virtual_tun_write)(Box::new(|b: &mut [u8]| {
            r = f(b);
        }), len);
        r
    }
}

Error:

   Compiling playground v0.0.1 (/playground)
error[E0310]: the parameter type `R` may not live long enough
  --> src/lib.rs:15:50
   |
10 |     fn consume<R, F>(self, len: usize, f: F) -> Result<R,()>
   |                - help: consider adding an explicit lifetime bound...: `R: 'static`
...
15 |         let result = (self.on_virtual_tun_write)(Box::new(|b: &mut [u8]| {
   |                                                  ^^^^^^^^ ...so that the reference type `&mut std::result::Result<R, ()>` does not outlive the data it points at

error[E0310]: the parameter type `R` may not live long enough
  --> src/lib.rs:15:50
   |
10 |       fn consume<R, F>(self, len: usize, f: F) -> Result<R,()>
   |                  - help: consider adding an explicit lifetime bound...: `R: 'static`
...
15 |           let result = (self.on_virtual_tun_write)(Box::new(|b: &mut [u8]| {
   |  __________________________________________________^
16 | |             r = f(b);
17 | |         }), len);
   | |__________^ ...so that the type `[closure@src/lib.rs:15:59: 17:10]` will meet its required lifetime bounds

error[E0310]: the parameter type `F` may not live long enough
  --> src/lib.rs:15:50
   |
10 |       fn consume<R, F>(self, len: usize, f: F) -> Result<R,()>
   |                     - help: consider adding an explicit lifetime bound...: `F: 'static`
...
15 |           let result = (self.on_virtual_tun_write)(Box::new(|b: &mut [u8]| {
   |  __________________________________________________^
16 | |             r = f(b);
17 | |         }), len);
   | |__________^ ...so that the type `[closure@src/lib.rs:15:59: 17:10]` will meet its required lifetime bounds

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0310`.
error: could not compile `playground`

To learn more, run the command again with --verbose.

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=a610b15f48c8217274a75a4d03c76380

Let me begin by this error:

so that the reference type `&mut std::result::Result<R, ()>` does not outlive the data it points at

Why a reference? f returns std::result::Result<R, ()> , not a reference. So I don't see why it treats it like a mutable reference.

Also, as I can crearly see, r lives more than the Box and the closure inside the Box

Why a reference?

The closure is capturing r by reference; you could avoid it by using the move keyword. However, you want it to be a reference since you still want to use it afterwards.


A big constraint causing your problems stems from the fact that trait objects are 'static by default. This is specifically a problem since the boxed closure you want to pass to on_virtual_tun_write has references (which are not 'static ), which is why you get the errors you see.

You can fix this by making the inner trait generic over any lifetime.

pub type OnVirtualTunWrite = Arc<dyn for<'a> Fn(Box<dyn FnOnce(&mut [u8]) + 'a>, usize) -> Result<(), ()> + Send + Sync>;
                                  // ^^^^^^^                              ^^^^

Fixing this problem exposes others though:

error[E0594]: cannot assign to `r`, as it is not declared as mutable
  --> src/lib.rs:16:13
   |
14 |         let r: Result<R,()>;
   |             - help: consider changing this to be mutable: `mut r`
15 |         let result = (self.on_virtual_tun_write)(Box::new(|b: &mut [u8]| {
16 |             r = f(b);
   |             ^ cannot assign

error[E0381]: borrow of possibly-uninitialized variable: `r`
  --> src/lib.rs:15:59
   |
15 |         let result = (self.on_virtual_tun_write)(Box::new(|b: &mut [u8]| {
   |                                                           ^^^^^^^^^^^^^^ use of possibly-uninitialized `r`
16 |             r = f(b);
   |             - borrow occurs due to use in closure

You cannot capture a potentially uninitialized value in a closure. A common way to fix this is to use Option :

let mut r: Option<Result<R,()>> = None;
let result = (self.on_virtual_tun_write)(Box::new(|b: &mut [u8]| {
    r = Some(f(b));
}), len);
r.unwrap()

This also covers the potential problem that on_virtual_tun_write may not even call the given function needed to initialize r . As I've presented, it would panic in that case, but handling that issue would be up to you.

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