I'm trying to define a trait with a function that returns an associated type with the same lifetime as one parameter.
Conceptually something like the following (which doesn't work: lifetime parameter not allowed on this type [Self::Output]
):
trait Trait {
type Output;
fn get_output<'a>(&self, input: &'a i32) -> Self::Output<'a>;
}
I found several questions about lifetimes for associated types on Stack Overflow and the Internet, but none seem to help. Some suggested defining the lifetime on the whole trait:
trait Trait<'a> {
type Output;
fn get_output(&self, input: &'a i32) -> Self::Output;
}
but this doesn't work either: it compiles, but then the following function fails to compile:
fn f<'a, T>(var: &T)
where T: Trait<'a>
{
let input = 0i32;
let output = var.get_output(&input);
}
giving an error:
error: `input` does not live long enough
--> <anon>:9:35
|
| let output = var.get_output( &input );
| ^^^^^ does not live long enough
| }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the body at 7:48...
--> <anon>:7:49
|
| fn f<'a, T>( var : &T ) where T : Trait<'a> {
| _________________________________________________^ starting here...
| | let input = 0i32;
| | let output = var.get_output( &input );
| | }
| |_^ ...ending here
How should I define the trait so that it behaves the way I want?
This is currently impossible, even in nightly Rust.
This requires some form of Higher Kinded Types (HKT), and the current approach envisaged is dubbed Associated Type Constructor (ATC).
The main motivation for introducing ATC is actually this very usecase.
With ATC, the syntax would be:
trait Trait {
type Output<'a>;
fn get_output<'a>(&self, input: &'a i32) -> Self::Output<'a>;
}
Note: if you wish to learn about ATCs, see Niko's series of articles.
For the particular example you have, you can work around this with HRTB (Higher Ranked Traits Bounds) as noted by Shepmaster:
fn f<T>(var: &T)
where for<'a> T: Trait<'a>
{ ... }
however this is fairly limited (notably, limited to trait bounds).
This requires using higher-ranked trait bounds:
fn f<T>(var: &T)
where for<'a> T: Trait<'a>
{
let input = 0i32;
let output = var.get_output(&input);
}
See also:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With