GAT
- Rust course
- Advanced
- Lesson 62/81
- 4 min
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 merhabaWithout GATs an associated type can't take a lifetime; you'd have to return a copy on each call or change the design.
Practice 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.
Starter code
fn main() {
// buraya yaz
}Sample 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());
}Expected output
3 merhaba
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 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 Correct answer
- Convention
- For speed
Explanation: The compiler requires this bound on GAT declarations, so the borrowed value can't outlive the source.
2 Associated type with a lifetime
trait Bakilabilir {
type Bakis____ where Self: 'a;
fn bak<'a>(&'a self) -> Self::Bakis<'a>;
}
trait Bakilabilir {
type Bakis<'a> where Self: 'a;
fn bak<'a>(&'a self) -> Self::Bakis<'a>;
}
Explanation: A GAT adds a generic parameter to the associated type.
3 Implementation and Bakis type
| Term | Meaning |
|---|---|
Kutu(Vec<i32>) |
&'a [i32] |
Metin(String) |
&'a str |
Iterator::Item |
Not a GAT |
type Bakis<'a> |
GAT |