The problem here is that the type of y
is GenVal<S1>
, so you can only put S1
in it. It's just like a Vec
, you don't just have a Vec
that you can put whatever in, you might have a Vec<i32>
that you can only put integers of the type i32
in.
It is not possible to put any kind of T1
directly inside GenVal
, because then it is not possible for the compiler to figure out how large the GenVal
struct is (in bytes). The solution to this is to use a Box
, which the T1
on the heap, and puts an 8 byte pointer inside the GenVal
struct.
Using a box looks like this:
struct GenVal {
gen_val: Box<dyn T1>,
}
trait T1 {
fn one() -> Self where Self: Sized;
}
#[derive(Default)]
struct S1 {}
impl T1 for S1 {
fn one() -> Self {
S1 {}
}
}
#[derive(Default)]
struct S2 {}
impl T1 for S2 {
fn one() -> Self {
S2 {}
}
}
impl GenVal {
fn new<T: T1 + 'static>() -> Self {
Self {
gen_val: Box::new(T::one()),
}
}
fn set_gen_val<T: T1 + 'static>(&mut self, gen_val: T) {
self.gen_val = Box::new(gen_val);
}
}
fn main() {
let mut y = GenVal::new::<S1>();
y.set_gen_val(S2::default());
}
Note that GenVal
is no longer generic, because you don't fix it on any type any longer.
Regarding the 'static
you see on the methods on GenVal
, it is because you might define a type like this:
struct SWithLifetime<'a> {
pointer_to_somewhere_else: &'a i32,
}
This type contains a pointer, and therefore can't outlive that pointer. If you were to put it in GenVal
, you would loose the information regarding how long it may live, and therefore we must require 'static
, which disallows things with lifetimes like that.
This wasn't an issue before, because the type would just look like this: GenVal<SWithLifetime<'a>>
, so the information wasn't lost.