Rust
GAT
Learn Generic Associated Types (GATs).
GATs
Generic associated types (GATs) let the associated type itself take a generic parameter (usually a lifetime). This way a trait can return a view type borrowing from self:
trait Bakilabilir {
type Bakis<'a> where Self: 'a;
fn bak<'a>(&'a self) -> Self::Bakis<'a>;
}
struct Kutu(Vec<i32>);
impl Bakilabilir for Kutu {
type Bakis<'a> = &'a [i32];
fn bak<'a>(&'a self) -> &'a [i32] { &self.0 }
}
GATs became stable with Rust 1.65; they make previously unwritable abstractions like "lending iterators" possible.
Different views
The same trait can return different borrowed views for different types:
struct Metin(String);
impl Bakilabilir for Metin {
type Bakis<'a> = &'a str;
fn bak<'a>(&'a self) -> &'a str { &self.0 }
}
let k = Kutu(vec![1, 2, 3]);
let m = Metin(String::from("merhaba"));
println!("{} {}", k.bak().len(), m.bak()); // 3 merhaba
Without GATs an associated type can't take a lifetime; you'd have to return a copy on each call or change the design.
Exercise Borrowed views
Implement the Bakilabilir trait above for Kutu(Vec<i32>) and Metin(String). Print the results of Kutu(vec![1, 2, 3]).bak().len() and Metin("merhaba").bak() separated by a space.
Show example solution
trait Bakilabilir {
type Bakis<'a>
where
Self: 'a;
fn bak<'a>(&'a self) -> Self::Bakis<'a>;
}
struct Kutu(Vec<i32>);
struct Metin(String);
impl Bakilabilir for Kutu {
type Bakis<'a> = &'a [i32];
fn bak<'a>(&'a self) -> &'a [i32] {
&self.0
}
}
impl Bakilabilir for Metin {
type Bakis<'a> = &'a str;
fn bak<'a>(&'a self) -> &'a str {
&self.0
}
}
fn main() {
let k = Kutu(vec![1, 2, 3]);
let m = Metin(String::from("merhaba"));
println!("{} {}", k.bak().len(), m.bak());
}
Test yourself
-
Why is <code>where Self: 'a</code> needed?
- It isn't needed
- Since the view lives for 'a, Self must live at least that long too
- Convention
- For speed
Show answer
Since the view lives for 'a, Self must live at least that long too — The compiler requires this bound on GAT declarations, so the borrowed value can't outlive the source.
-
Associated type with a lifetime
trait Bakilabilir {
type Bakis____ where Self: 'a;
fn bak<'a>(&'a self) -> Self::Bakis<'a>;
}
Show answer
trait Bakilabilir {
type Bakis<'a> where Self: 'a;
fn bak<'a>(&'a self) -> Self::Bakis<'a>;
}
-
Implementation and Bakis type
- Kutu(Vec<i32>)
- &'a [i32]
- Metin(String)
- &'a str
- Iterator::Item
- Not a GAT
- type Bakis<'a>
- GAT
Next lesson: Supertrait