Hi,
I am writing a program that allow users to define arbitrary mathematical functions to compute some values. But I have an issue of specifying lifetime for struct that is used as generic type. Here is a minimal example that demonstrate it, so overall, I have models, which have list of functions, and a function can compute value from variables
pub trait Function<V> {
fn exec(&self, var: &V);
}
pub struct Variable<'a> {
name: &'a str,
}
pub struct FunctionImpl {
}
impl<'a> Function<Variable<'a>> for FunctionImpl {
fn exec(&self, var: &Variable<'a>) {
println!("exec func");
}
}
pub struct Model<V> {
funcs: Vec<Box<Function<V>>>,
}
impl<V> Model<V> {
pub fn new(funcs: Vec<Box<Function<V>>>) -> Model<V> {
Model { funcs }
}
pub fn exec(&self, var: &V) {
println!("exec model");
}
}
The problem here is sometime structs implement V (like Variable struct) can contain references. Which make this code unable to compile.
fn main() {
let model = Model::new(vec![Box::new(FunctionImpl {})]);
{
let example = Variable {
name: "someone",
};
model.exec(&example);
}
{
let x = "someoneelse".to_owned();
let example = Variable {
name: &x,
};
model.exec(&example);
}
}
Error:
59 | name: &x,
| ^ borrowed value does not live long enough
...
62 | }
| - `x` dropped here while still borrowed
...
65 | }
| - borrowed value needs to live until here
Which I think life time 'a of trait Function bounded outside, so it is outlive lifetime of x. However, since I cannot store any value of V inside Function (func exec is immutable), and model; I was hope that Rust can detect that lifetime 'a only bound to the function exec
, and can cast life time 'a to the shorter lifetime of x.
Also, I found this code can compile well.
fn main() {
let func = FunctionImpl {};
{
let example = Variable {
name: "someone",
};
func.exec(&example);
}
{
let x = "someoneelse".to_owned();
let example = Variable {
name: &x,
};
func.exec(&example);
}
}
I got one solution that use Rc/Arc for reference, so I don't need lifetime. However, I want to avoid it because I may have to deal with creating millions of variables, so Rc/Arc can be costly.
My question is: how can I overcome this problem? Is Rust actually correct to prevent possible error with this design?
Thank you for your time! Any help is greatly appreciate!