Reputation: 823
title seems to be similar with Lifetime parameter for `Self` in trait signature but I create this new post because I believe root cause is different.
I have a trait like following
trait T<'a> {
fn new(y: &'a Y) -> Self where Self: Sized;
fn do_something(&self);
}
and want to write generic function that accept type X (which implements trait T<'a>), and reference of Y, then create dyn Trait T<'a>.
fn create_t_from_i<'a, I: T<'a>>(y: &'a Y) -> Box<dyn T<'a>>
my naive implementation is like this
fn create_t_from_i<'a, I: T<'a>>(y: &'a Y) -> Box<dyn T<'a>> {
return Box::new(I::new(y)) as Box<dyn T<'a>>;
}
then I got this error.
error[E0310]: the parameter type `I` may not live long enough
but parameter type I
has constraint T<'a>
, I don't figure out why this does not tell rustc
to I::new(y)
is alive after execution step go out from this function.
I suspect this is happened by I:new()
returns Self
, which has no lifetime annotation. but also I cannot find the way to give lifetime annotation to Self.
this is full example to cause the error.
struct Y {
z: i32
}
struct X<'a> {
y: &'a Y
}
trait T<'a> {
fn new(y: &'a Y) -> Self where Self: Sized;
fn do_something(&self);
}
impl<'a> T<'a> for X<'a> {
fn new(y: &'a Y) -> X<'a> {
return X::<'a> {
y: y
}
}
fn do_something(&self) {
println!("{}", self.y.z)
}
}
fn create_t_from_i<'a, I: T<'a>>(y: &'a Y) -> Box<dyn T<'a>> {
// error: the parameter type `I` may not live long enough
return Box::new(I::new(y)) as Box<dyn T<'a>>;
}
fn main() {
let y = Y { z: 123 };
{
let t = create_t_from_i::<X>(&y);
t.do_something()
}
}
if I remove definition of T::new and giving X::new to create_t_from_i as function pointer, code seems work (need to use T + 'a instead of T<'a>). but what essential difference is from 1st example?
struct Y {
z: i32
}
struct X<'a> {
y: &'a Y
}
trait T {
fn do_something(&self);
}
impl<'a> X<'a> {
fn new(y: &'a Y) -> X<'a> {
return X::<'a> {
y: y
}
}
}
impl<'a> T for X<'a> {
fn do_something(&self) {
println!("{}", self.y.z)
}
}
fn create_t_from_i<'a, I: T + 'a>(ctor: fn (y: &'a Y) -> I, y: &'a Y) -> Box<dyn T + 'a> {
// if passing constructor function directly and using annotation I: T + 'a, rustc does not complain.
let i = ctor(y);
return Box::new(i) as Box<dyn T + 'a>;
}
fn main() {
let y = Y { z: 123 };
{
let t = create_t_from_i::<X>(X::new, &y);
t.do_something()
}
}
anyone have an idea why this happens and how to make `rustc' happy?
regards.
Upvotes: 0
Views: 169
Reputation: 240
Any trait object has a lifetime annotations, which will implicitly be 'static
.
Your function is thus:
fn create_t_from_i<'a, I: T<'a>>(y: &'a Y) -> Box<dyn 'static + T<'a>>
The solution is to explicitly annotate your trait object's lifetime:
fn create_t_from_i<'a, I: 'a + T<'a>>(y: &'a Y) -> Box<dyn 'a + T<'a>>
Upvotes: 0
Reputation: 40884
fn create_t_from_i<'a, I: T<'a>>(y: &'a Y) -> Box<dyn T<'a>>
is implicitly the same as
fn create_t_from_i<'a, I: T<'a>>(y: &'a Y) -> Box<dyn 'static + T<'a>>
which in turns means that I
must also have a static lifetime to be able to store it in the returned box (i.e. you need a I: 'static
bound).
To solve this, you can add another lifetime parameter for the lifetime of I
, and use that in the returned boxed trait. This will work no matter what the lifetime of I
actually is:
fn create_t_from_i<'a, 'b, I: 'b + T<'a>>(y: &'a Y) -> Box<dyn 'b + T<'a>>
// ^^^^^^^^^ ^^^^
Upvotes: 2