Reputation: 511
Simplified code:
struct A(/**/);
trait Foo {}
trait Bar {
fn bar(a: &A) -> impl Foo;
fn baz() -> impl Foo {
let a = A();
Self::bar(&a)
}
}
Error:
error[E0597]: `a` does not live long enough
--> src/lib.rs:10:19
|
9 | let a = A();
| - binding `a` declared here
10 | Self::bar(&a)
| ----------^^-
| | |
| | borrowed value does not live long enough
| argument requires that `a` is borrowed for `'static`
11 | }
| - `a` dropped here while still borrowed
It can be resolved by returning a concrete type that implements Foo
or Box<dyn Foo>
instead of impl Foo
, but I want to keep returning impl Foo
without introducing additional overhead.
Examples that work but I don't want:
struct A(/**/);
trait Foo {}
struct B;
impl Foo for B {}
trait Bar {
fn bar(a: &A) -> B;
fn baz() -> impl Foo {
let a = A();
Self::bar(&a)
}
}
struct A(/**/);
trait Foo {}
trait Bar {
fn bar(a: &A) -> Box<dyn Foo>;
fn baz() -> Box<dyn Foo> {
let a = A();
Self::bar(&a)
}
}
Upvotes: 1
Views: 149
Reputation: 323
According to rfc 3498
the opaque return type will automatically capture all trait input type and lifetime parameters, all type and lifetime parameters present in the Self type, and all type and lifetime parameters in the associated function or method signature.
the code can be desugar like this:
trait Bar {
fn bar<'a>(a: &'a A) -> impl Foo + 'a;
fn baz() -> impl Foo {
let a = A();
Self::bar(&a)
}
}
baz
expects to return impl Foo
while bar
returns impl Foo + 'a
, so the compiler complains borrowed value does not live long enough
The code in this answer works because the return type Self::BarRet
of bar
has no generic lifetime parameters, which means return value of bar
has nothing to do with the lifetime of its parameter &A
Upvotes: 4
Reputation: 793
I don't fully understand why it doesn't work, but a workaround is to make the return type an associated type to the trait:
struct A(/**/);
trait Foo {}
trait Bar {
type BarRet: Foo;
fn bar(a: &A) -> Self::BarRet;
fn baz() -> impl Foo {
let a = A();
Self::bar(&a)
}
}
Upvotes: 3