1

I'm working with callbacks on my struct, using boxed closures. However, I haven't been able to figure out how to call one closure from another:

struct MyStruct {
    first: Box<Fn()>,
    second: Box<Fn()>,
}

impl MyStruct {
    fn method(&mut self) {
        self.second = Box::new(|| {
            // How can I make this work?
            (self.first)();
        });
    }
}

fn main() {
    let _ = MyStruct {
        first: Box::new(|| {}),
        second: Box::new(|| {}),
    };
}

This gives:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/main.rs:8:32
   |
8  |           self.second = Box::new(|| {
   |  ________________________________^
9  | |             // How can I make this work?
10 | |             (self.first)();
11 | |         });
   | |_________^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 7:5...
  --> src/main.rs:7:5
   |
7  | /     fn method(&mut self) {
8  | |         self.second = Box::new(|| {
9  | |             // How can I make this work?
10 | |             (self.first)();
11 | |         });
12 | |     }
   | |_____^
   = note: ...so that the types are compatible:
           expected &&mut MyStruct
              found &&mut MyStruct
   = note: but, the lifetime must be valid for the static lifetime...
   = note: ...so that the expression is assignable:
           expected std::boxed::Box<(dyn std::ops::Fn() + 'static)>
              found std::boxed::Box<dyn std::ops::Fn()>

I'm not quite sure what that means in this context.

I understand that the borrowing rules are the cause of the error, but is there any legal way in Rust to get the same effect of what I'm going for?

I'm not sure if it makes sense just from this why I would want to do this. It's a minimal reproduction. I can provide a bigger example, but it's much more involved.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
anderspitman
  • 9,230
  • 10
  • 40
  • 61
  • 3
    You're trying to store a reference to `self.first` (because you capture it) in `self.second`, that cannot work. – mcarton Jan 06 '19 at 16:51
  • Ok that makes sense, and seems obvious now that you say it. I've been in the weeds with this for many hours. It took a while to drill down to this point. Now, is there a way to accomplish the same effect in Rust? Is there some way for `second` to borrow `first` whenever it needs it, or something along those lines? – anderspitman Jan 06 '19 at 16:55

1 Answers1

1

Here is a partial solution to your problem: Do not take Box<Fn()>, but use Box<Fn(&MyStruct)> instead, i.e. pass the "self" explicitly to the closures.

However, as far as I can see, this only allows the closures to take &MyStruct (as opposed to &mut MyStruct), i.e. the closures cannot modify the given MyStruct (which may or may not be enough for your use case).

struct MyStruct {
    first: Box<Fn(&MyStruct)>,
    second: Box<Fn(&MyStruct)>,
}

impl MyStruct {
    fn method(&mut self) {
        self.second = Box::new(|self2: &MyStruct| {
            (self2.first)(self2)
        });
    }
}

fn main() {
    let _ = MyStruct {
        first: Box::new(|_self_ignored| {}),
        second: Box::new(|_self_ignored| {}),    
    };
}

If the closures should modify MyStruct, you run into problems with (self2.first)(self2), since this would then borrow self2 twice, once of them mutably. You could possibly get around this by swapping out first/second temporarily, but this way, you would need to be terribly careful whenever you call first/second, since it could at any time be impossible to call first/second.

There may be unsafe ways around this. That said, I suppose (or at least, I hope) there is a better way to implement what you are trying to achieve.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
phimuemue
  • 34,669
  • 9
  • 84
  • 115