Supertraits
A supertrait is a prerequisite trait bound declared on another trait (trait Subtrait: Supertrait), requiring any type that implements Subtrait to also implement Supertrait and allowing default methods in Subtrait to call methods from Supertrait.
Declaring and Implementing Supertraits
use std::fmt;
// `OutlinePrint` requires `Self` to implement `fmt::Display`:
trait OutlinePrint: fmt::Display {
fn outline_print(&self) {
let output = self.to_string(); // Provided by Display
let len = output.len();
println!("{}", "*".repeat(len + 4));
println!("* {output} *");
println!("{}", "*".repeat(len + 4));
}
}
struct Point {
x: i32,
y: i32,
}
impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
impl OutlinePrint for Point {}
fn main() {
let p = Point { x: 3, y: 7 };
p.outline_print();
}
**********
* (3, 7) *
**********
Note that trait Sub: Super is syntactic sugar for trait Sub where Self: Super. Rust does not have class inheritance—implementing Sub does not automatically implement Super; you must write a separate impl Super for Type block (or #[derive(...)] it).
Missing Supertrait Implementation Error (E0277)
Attempting to implement a subtrait on a type that does not implement its supertrait fails with E0277:
// ❌ does not compile
trait Identifiable {
fn id(&self) -> u64;
}
trait Auditable: Identifiable {
fn audit_log(&self) -> String {
format!("audited item #{}", self.id())
}
}
struct Invoice;
impl Auditable for Invoice {}
fn main() {}
error[E0277]: the trait bound `Invoice: Identifiable` is not satisfied
--> src/main.rs:14:20
|
14 | impl Auditable for Invoice {}
| ^^^^^^^ the trait `Identifiable` is not implemented for `Invoice`
|
note: required by a bound in `Auditable`
--> src/main.rs:6:18
|
6 | trait Auditable: Identifiable {
| ^^^^^^^^^^^^ required by this bound in `Auditable`
Trait Object Upcasting (&dyn Subtrait to &dyn Supertrait)
Starting in Rust 1.86 (and standard in the 2024 edition), a trait object for a dyn-compatible subtrait (&dyn Subtrait or Box<dyn Subtrait>) can be implicitly coerced (upcast) to a trait object of any of its dyn-compatible supertraits (&dyn Supertrait or Box<dyn Supertrait>):
trait Base {
fn base_name(&self) -> &str;
}
trait Derived: Base {
fn extra_info(&self) -> u32;
}
struct Service;
impl Base for Service {
fn base_name(&self) -> &str {
"auth-service"
}
}
impl Derived for Service {
fn extra_info(&self) -> u32 {
200
}
}
fn main() {
let d: &dyn Derived = &Service;
let b: &dyn Base = d; // Trait upcasting from &dyn Derived to &dyn Base
println!("Base name: {}, extra: {}", b.base_name(), d.extra_info());
}
Base name: auth-service, extra: 200