I'm trying to wrap some logic common to many Monte Carlo calculations in a Mutator
, which contains a set of possible random Mutation
s that can be applied to a Configuration
struct. Each Mutation
generates a Demutation
operation that reverts it. While the Mutation
requires a random number generator to operate, the Demutation
is fully deterministic and does not.
Here's a very minimal definition of the relevant components:
use rand::Rng;
type MutatorResult<T> = Result<T, ()>;
trait Configuration {}
trait Mutation<C: Configuration> {
fn execute(&self, configuration: &mut C, rng: &mut impl Rng) -> MutatorResult<Box<dyn Demutation<C>>>;
}
trait Demutation<C: Configuration> {
fn execute(&self, c: &mut C) -> MutatorResult<()>;
}
A simple Configuration
might look like this, for example:
struct ConfigurationImpl {
x: f64,
}
impl ConfigurationImpl {
fn displace(&mut self, shift: f64) {
self.x += shift;
}
fn random_displace_right(&mut self, rng: &mut impl Rng) -> impl Fn(&mut Self) {
let shift: f64 = rng.gen();
self.displace(shift);
move |c: &mut ConfigurationImpl| c.displace(-shift)
}
}
impl Configuration for ConfigurationImpl {}
Now, when I try to implement a Mutation
, I run into a problem like this:
struct MyDemutation {
undo_closure: Box<dyn Fn(&mut ConfigurationImpl)>
}
impl Demutation<ConfigurationImpl> for MyDemutation {
fn execute(&self, c: &mut ConfigurationImpl) -> MutatorResult<()> {
(self.undo_closure)(c);
Ok(())
}
}
struct MyMutation {}
impl Mutation<ConfigurationImpl> for MyMutation {
fn execute(&self, configuration: &mut ConfigurationImpl, rng: &mut impl Rng) -> MutatorResult<Box<dyn Demutation<ConfigurationImpl>>> {
// This works:
// let undo_closure = Box::new({
// let shift: f64 = rng.gen();
// configuration.displace(shift);
// move |c: &mut ConfigurationImpl| c.displace(-shift)
// });
// But this doesn't compile:
let undo_closure = Box::new(configuration.random_displace_right(rng));
Ok(Box::new(MyDemutation { undo_closure }))
}
}
The result is:
error[E0310]: the parameter type `impl Rng` may not live long enough
--> src/lib.rs:94:40
|
83 | ...guration: &mut ConfigurationImpl, rng: &mut impl Rng) -> MutatorResult<Box<dyn Demutation<ConfigurationImpl>>> {
| -------- help: consider adding an explicit lifetime bound...: `impl Rng + 'static`
...
94 | ...ation { undo_closure }))
| ^^^^^^^^^^^^ ...so that the type `impl Fn(&mut ConfigurationImpl)` will meet its required lifetime bounds
For more information about this error, try `rustc --explain E0310`.
How do I tell Rust that the lifetime of the Rng reference is not at all relevant here?
This Playground link contains the code, and a bit more code for the Mutator
itself, where I was able to rely on the answer to this question to decouple the random number generator from the struct definitions.