2

If I have a closure, I can move || ... to move data into the closure context, like this:

#[derive(Debug)]
struct State {
    value: usize,
}

fn external_receiver(mut inc: impl FnMut() -> usize) {
    let x = inc();
    println!("{:?}", x);

    let x = inc();
    println!("{:?}", x);
}

fn main() {
    let mut foo = Box::new(State { value: 0 });
    external_receiver(move || -> usize { 
        foo.as_mut().value += 1;
        return foo.as_ref().value;
    });
}

I have a few situations where it would be convenient to have a closure that could return a &mut State reference to some data object, where the caller of the closure was totally naive about the source of the object.

I can't get anything like that to work though:

#[derive(Debug)]
struct State {
    value: usize,
}

fn external_receiver(inc: impl Fn() -> &mut State) {
    let x = inc();
    x.value += 1;
    println!("{:?}", x);
}

fn main() {
    let mut foo = Box::new(State { value: 0 });
    external_receiver(move || -> &mut State { foo.as_mut() });
}

There doesn't seem to any obvious way around this; I can't seem to figure out how to assert that the lifetime of the returned reference (&'a mut State) should be equal to the lifetime of the closure itself.

I've tried a couple of variations like passing a reference:

fn external_receiver<'a>(inc: &'a mut FnMut() -> &'a mut State) {
    let x = inc();
    x.value += 1;
    println!("{:?}", x);
}

fn main() {
    let mut foo = Box::new(State { value: 0 });
    let mut x = move || -> &mut State { foo.as_mut() };
    external_receiver(&mut x);
}

...but I get the typical:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> src/main.rs:14:45
   |
14 |     let mut x = move || -> &mut State { foo.as_mut() };
   |                                             ^^^^^^
   |
note: first, the lifetime cannot outlive the lifetime  as defined on the body at 14:17...
  --> src/main.rs:14:17
   |
14 |     let mut x = move || -> &mut State { foo.as_mut() };
   |                 ^^^^^^^^^^^^^^^^^^^^^
note: ...so that closure can access `foo`
  --> src/main.rs:14:41
   |
14 |     let mut x = move || -> &mut State { foo.as_mut() };
   |                                         ^^^
note: but, the lifetime must be valid for the call at 15:5...
  --> src/main.rs:15:5
   |
15 |     external_receiver(&mut x);
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that argument is valid for the call
  --> src/main.rs:15:23
   |
15 |     external_receiver(&mut x);
   |                       ^^^^^^

Does moving data to a closure not actually move the data into the closure itself (even if the closure is boxed?)?

Is there some way to be able to have a function that basically does Fn() -> &Foo?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Doug
  • 32,844
  • 38
  • 166
  • 222

0 Answers0