I have a piece of rust code whereby I iteratively call a function repeatedly, iteration shown below.
impl MainStruct {
fn iteration(
&mut self,
x: &Vec<f64>,
y: &Vec<f64>,
) -> Vec<f64> {
// Generate a
let parameters = parameter_function();
let a = A::default(
parameters
);
a.update(x, y);
// Define the closure
let closure = move |x: &[f64]| {
let res = a.method_of_a(&x.to_vec());
res.0 - res.1
};
// Create b struct
let b = B::new(&closure);
// Create c struct
let c = C::new(vec![b]);
// Initialise D struct
let mut d = D::new();
// Get res
let res = function(&c, &mut d);
// do stuff
}
}
In each iteration I am initialising 4 structures, A, B, C and D, but A and D are initialised the same for every iteration. I have tried to make a and d fields of my main struct, and make them initialised when MainStruct is initialised, however in doing so I get lifetime errors, stating that the lifetime of &mut self is lifetime 1 and that 'let b = B::new(&closure);' cast requires 1 must outlive static.
impl MainStruct {
fn iteration(
&mut self,
x: &Vec<f64>,
y: &Vec<f64>,
) -> Vec<f64> {
self.a.update(x, y);
// Define the closure
let closure = move |x: &[f64]| {
let res = self.a.method_of_a(&x.to_vec());
res.0 - res.1
};
// Create b struct
let b = B::new(&closure);
// Create c struct
let c = C::new(vec![b]);
// Get res
let res = function(&c, &mut self.d);
// do stuff
}
}
any ideas on how to fix this issue? (side note, I am coming from a python background, so if my approach is not the "rust way", please let me know)
This question provides incomplete information. Judging by your error description
the function signature of B::new seems quite relevant, or whatever else the source of the 'static constraint is. Additionally, a full compiler error is always very appreciated, especially for cases like this where you don’t provide a fully reproducible code example. You paraphrase the error, but it’s always possible that the full error message contains useful details that are being missed this way.
The next step then is that we’ll need to figure out whether that constraint is necessary or not, which determines whether the fix needs to happen inside this function, or maybe in the signature of B::new and/or elsewhere. I’d question the necessity given that you work with a (short lived) reference to the closure in the first place.
this error indicates the definition of your B::new<F>(f: F) must have a F: 'static bounds, but your closure captures self.a, which is behind of mutable borrow with some lifetime (let's call it 'a as in &'a mut self), so the closure also contains a lifetime of 'a.
depending on the situation, there's two direction to fix this, either:
a) remove the 'static bounds for the parameter type of B::new(), or if the implementation requires 'static, the only options left is
b) don't capture self.a in the closure, you can either make a clone of a or just revert back to the original code
regarding whether the code is idiomatic, it's hard to say for sure from the reduced code snippets without knowing what the code actually meant to work. but just an minor observation: the parameter type for x and y can probably use slices instead of references of Vec (unless of course you need to call certain Vec specific methods).
/// Define B.
pub struct B<'a> {
pub handler: &'a dyn Fn(&[f64]) -> f64,
}
impl<'a> B<'a> {
/// Instantiates a new `B`.
pub fn new(handler: &'a MyClosure) -> Self {
B {
handler: handler,
}
}
}
the results might have been less compilation errors. (Also, you probably also want to remove the move from the closure eventually, which I suppose was added due to compiler suggestions stemming from the 'static constraint, too).'
While the above may seem identical to your code it’s not.
type MyClosure = dyn Fn(&[f64]) -> f64;
has an elided trait object lifetime and stands for
type MyClosure = dyn Fn(&[f64]) -> f64 + 'static;
whereas the same trait-object-lifetime elision rules make
&'a dyn Fn(&[f64]) -> f64
stand for
&'a (dyn Fn(&[f64]) -> f64 + 'a)
which is less restrictive than
&'a (dyn Fn(&[f64]) -> f64 + 'static)
In order to keep the type synonym, you could do this instead: