Required Bounds on Generic Associated Types
Generic associated types often need explicit where Self: 'a bounds because the trait methods prove those bounds at use sites.
Writing the required bounds on the GAT preserves the implementer’s freedom to return borrowed associated types.
What it is
A Generic Associated Types declaration can have its own lifetime, type, and const parameters.
When a trait method returns Self::Item<'a> from &'a self or &'a mut self, the compiler can prove Self: 'a inside that method signature.
Rust currently requires such provable bounds to be repeated on the GAT declaration.
The familiar shape is type Item<'a> where Self: 'a;.
This rule looks redundant at first, but it allows implementers to define associated types that borrow from Self.
Without the bound on the GAT itself, some valid impl definitions would be rejected.
The Reference notes that these rules may be loosened in the future, so treat them as a current language requirement.
The rule is central to lending iterators, streaming parsers, and view APIs.
How it works
Required GAT bounds are derived from how the GAT appears in trait methods.
If a method has fn next<'a>(&'a mut self) -> Self::Item<'a>, then the receiver proves Self: 'a.
The GAT declaration must include where Self: 'a.
When several methods mention the same GAT, Rust uses the intersection of bounds that are true at all relevant uses, not the union.
Bounds can propagate through other associated type bounds.
For example, type Iter<'a>: Iterator<Item = Self::Item<'a>> where Self: 'a; carries the same relationship.
In impls, the associated type definition repeats the matching where clause.
This repetition is not aesthetic; it is part of the trait contract.
Example
trait LendingIterator {
type Item<'a>
where
Self: 'a;
fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
}
struct Windows<'data> {
data: &'data [u8],
pos: usize,
}
impl<'data> LendingIterator for Windows<'data> {
type Item<'a> = &'a [u8]
where
Self: 'a;
fn next<'a>(&'a mut self) -> Option<Self::Item<'a>> {
let end = self.pos.checked_add(2)?;
let window = self.data.get(self.pos..end)?;
self.pos += 1;
Some(window)
}
}
fn main() {
let mut windows = Windows { data: b"rust", pos: 0 };
assert_eq!(windows.next(), Some(&b"ru"[..]));
assert_eq!(windows.next(), Some(&b"us"[..]));
}Edge cases
trait View {
type Ref<'a>: Copy
where
Self: 'a;
fn view<'a>(&'a self) -> Self::Ref<'a>;
}
impl View for u32 {
type Ref<'a> = &'a u32 where Self: 'a;
fn view<'a>(&'a self) -> Self::Ref<'a> {
self
}
}
fn main() {
let n = 5_u32;
assert_eq!(*n.view(), 5);
}Best practice
- ✅ Start lending-style GATs with
type Item<'a> where Self: 'a;. - ✅ Repeat the where clause in the impl’s associated type definition.
- ✅ Use descriptive associated type names such as
Item,Ref,Guard,View, orIter. - ✅ Keep method signatures close to the GAT declaration so readers can see why the bound is required.
- ✅ Prefer GATs over unsafe lifetime extension when returned values borrow from
self. - ✅ Link GAT-heavy APIs to Lifetimes and Higher-Ranked Trait Bounds for readers who need the model.
Pitfalls
- ⚠️ Removing
where Self: 'abecause it “looks unused”; the trait may stop compiling or become less implementable. - ⚠️ Returning borrowed values through an ordinary associated type when a GAT is needed.
- ⚠️ Adding unnecessary bounds to the GAT that are only true for one method but not all uses.
- ⚠️ Expecting GATs to make every trait dyn-compatible; many such traits are not object safe.
- ⚠️ Confusing a GAT lifetime parameter with a lifetime chosen by the implementer; callers instantiate it at use sites.
See also
Advanced Type System Generic Associated Types Associated Types Trait Bounds Where Clauses Lifetimes Higher-Ranked Trait Bounds Lending Iterators with GATs Return-Position impl Trait in Traits dyn Compatibility (Object Safety)
Sources
- The Rust Reference, “Associated types” — the-reference, https://doc.rust-lang.org/reference/items/associated-items.html#associated-types
- The Rust Reference, “Required where clauses on generic associated types” — the-reference, https://doc.rust-lang.org/reference/items/associated-items.html#required-where-clauses-on-generic-associated-types
