Lifetime issue with closure

Probably not the right place to ask this, but what the hell. I've been battling with the borrow checker for too long. I'm try to pass a slice of f32s to a function that will use each one in a closure, but I have a lifetime problem I can't seem to solve. This code is part of an impl block for a funtion that implements a trait with a modify_amplitude function:

pub fn set_amplitudes(&mut self, weights: &[f32]) {
        for (i, v) in self.waves.iter_mut().enumerate() {
            v.0.modify_amplitude(Rc::new(|_| weights[i]));
        }
}

I'd guess the problem lies in the signature of modify_amplitude because there's nothing obviously wrong with the snippet you shared.

What exactly is the error?

add explicit lifetime 'static to the type of weights: &'static [f32]
but when i do this i get another error.

weights does not live long enough

fn modify_amplitude(&mut self, f: Rc<dyn Fn(f32) -> f32>) {
        for wave in self.waves.iter_mut() {
            wave.0.modify_amplitude(f.clone());
        }
   } 

It would really help if you would post the compile error.

error[E0597]: `weights` does not live long enough
   --> src/lib.rs:428:46
    |
428 |             v.0.modify_amplitude(Rc::new(|_| weights[i]));
    |                                  ------------^^^^^^^----
    |                                  |       |   |
    |                                  |       |   borrowed value does not live long enough
    |                                  |       value captured here
    |                                  cast requires that `weights` is borrowed for `'static`
429 |         }
430 |     }
    |     - `weights` dropped here while still borrowed

Also, here is the full code:

https://github.com/reedrosenbluth/swell/blob/modify/src/lib.rs#L420

What does modify_amplitude do? Why does it need a closure?

I need to be able to make arbitrary changes to amplitude. And depending on the type of "Wave" I'll pass different closures.

How about something like this:

pub fn set_amplitudes(weights: &[f32]) {
  for (i, v) in self.waves.iter_mut().enumerate() {
    let weight = weights[i];
    v.0.modify_amplitude(|_| weight);
  }
}

Thanks, i tried that. same problem

rror[E0597]: weight does not live long enough
--> src/lib.rs:429:46
|
429 | v.0.modify_amplitude(Rc::new(|_| weight));
| ------------^^^^^^-
| | | |
| | | borrowed value does not live long enough
| | value captured here
| cast requires that weight is borrowed for 'static
430 | }
431 | }
| - weight dropped here while still borrowed

I don't have any issue compiling this:

fn do_something<F: Fn() -> f32>(f: F) -> f32 {
  f()
}

pub fn set_something(values: &[f32]) {
  let _f = do_something(|| values[0]);
}

I think the problem you're having is because you're trying to wrap the closure in a reference counted type, which will require a lifetime for your weights reference. You would probably need to clone the weights and move them into the closure.

Try this:

fn modify_amplitude<'a>(&mut self, f: Rc<dyn Fn(f32) -> f32 + 'a>) {
    for wave in self.waves.iter_mut() {
        wave.0.modify_amplitude(f.clone());
    }
}

The issue is that modify_amplitude has this signature:

fn modify_amplitude(&mut self, f: Rc<dyn Fn(f32) -> f32>);

And when you use dyn Trait without specifying a lifetime, the compiler automatically inserts 'static. This means you've declared that it can only accept closures that contain no references to outside the closure. In your case, the closure contains a reference to weights, thus the error.

What are you trying to do? The closure will need to take ownership of something instead.

@trentj That will not work because weights doesn't live long enough for you to store a reference to it in the wave. For that to be the case, the weights reference would have to outlive the wave. You can't fix this issue by randomly inserting lifetimes in various places.

1 Like

I’d like to move each value in the weights slice into one closure in self.0.waves. The weights vector need not exist after.

The signature I suggested doesn't allow you to store the Rc inside self; it just relaxes the 'static bound. From glancing at the code it does not look as if the Rc is ever stored inside self, so it's analogous to

fn modify_amplitude(&mut self, f: &dyn Fn(f32) -> f32)

which is desugared to something like

fn modify_amplitude<'a>(&'a mut self, f: &'a dyn Fn(f32) -> f32 + 'a)

The next logical question, if that works, is why use Rc at all?

Do you need to modify the integer? What do you think of this?

pub fn set_amplitudes(&mut self, weights: &[f32]) {
    for (i, v) in self.waves.iter_mut().enumerate() {
        // make a copy
        let val = weights[i];
        // move the copy into the closure
        v.0.modify_amplitude(Rc::new(move |_| val));
    }
}

If you do need to modify it, please explain what operations you might need to perform.

No I don’t need to modify the number, But I tried your suggestion before asking for help and it doesn’t works.

If it doesn't work, how does it fail?

error[E0597]: val does not live long enough
--> src/lib.rs:430:46
|
430 | v.0.modify_amplitude(Rc::new(|_| val));
| ------------^^^-
| | | |
| | | borrowed value does not live long enough
| | value captured here
| cast requires that val is borrowed for 'static
431 | }
432 | }
| - val dropped here while still borrowed