Skip to content

Traits

Updated
17 Sept 2026
3 min read
0 sections
Page 3 of 18
Rust
rust
pub struct NewsArticle {
    pub headline: String,
    pub author: String,
    pub content: String,
}

impl NewsArticle {
    fn summarize(&self) -> String {
        format!("{} | by {}", self.headline, self.author)
    }
}

pub struct Tweet {
    pub username: String,
    pub content: String,
    pub reply: bool,
    pub retweet: bool,
}

impl Tweet {
    fn summarize(&self) -> String {
        format!("{}, @ {}", self.content, self.username)
    }
}

fn main() {
    let tweet = Tweet {
        username: String::from("@johndoe"),
        content: String::from("Hello, World !"),
        reply: false,
        retweet: false,
    };

    let article = NewsArticle {
        headline: String::from("Breaking News"),
        author: String::from("John Doe"),
        content: String::from("This is a breaking news article"),
    };

    println!("1 new tweet: {}", tweet.summarize());
    println!("New article available: {}", article.summarize());
}
Out · output
$ cargo run

1 new tweet: @johndoe, by Hello, World !
New article available: Breaking News, by John Doe (This is a breaking news article)
  • Traits are used to define shared behavior in an abstract way
  • trait{:rust} keyword is used to define a trait
rust
pub struct NewsArticle {
    pub headline: String,
    pub author: String,
    pub content: String,
}

impl Summary for NewsArticle {}

pub struct Tweet {
    pub username: String,
    pub content: String,
    pub reply: bool,
    pub retweet: bool,
}

impl Summary for Tweet {
    fn summarize(&self) -> String {
        format!("{}, by {}", self.username, self.content)
    }
}

pub trait Summary {
    fn summarize(&self) -> String {
        String::from("(Read more...)")
    }
}

fn main() {
   // --snip--
}
Out · output
$ cargo run

1 new tweet: @johndoe, by Hello, World !
New article available: (Read more...)
rust
pub trait Summary {
    fn summarize_author(&self) -> String;

    fn summarize(&self) -> String {
        format!("(Read more from {}...)", self.summarize_author())
    }
}

impl Summary for NewsArticle {
    fn summarize_author(&self) -> String {
        format!("@{}", self.author)
    }
}

impl Summary for Tweet {
    fn summarize_author(&self) -> String {
        format!("@{}", self.username)
    }

    fn summarize(&self) -> String {
        format!("{}, by {}", self.username, self.content)
    }
}
Out · output
$ cargo run

1 new tweet: @johndoe, by Hello, World !
New article available: (Read more from @John Doe...)
  • summarize_author{:rust} method is added to the Summary{:rust} trait, which is implemented by both NewsArticle{:rust} and Tweet{:rust} structs

Traits as Parameters

rust
pub fn notify(item: &impl Summary) {
    println!("Breaking news! {}", item.summarize());
}

fn main() {
    // --snip--

    notify(&tweet);
    notify(&article);
}
Out · output
$ cargo run

Breaking news! @johndoe, by Hello, World !
Breaking news! (Read more from @John Doe...)
  • impl Summary{:rust} is used as a parameter type for the notify{:rust} function
  • This allows the function to accept any type that implements the Summary{:rust} trait

Trait Bound Syntax

rust
pub fn notify<T: Summary>(item: &T) {
    println!("Breaking news! {}", item.summarize());
}

fn main() {
    // --snip--

    notify(&tweet);
    notify(&article);
}
  • T: Summary{:rust} is a trait bound, which specifies that T{:rust} must implement the Summary{:rust} trait

Multiple Trait Bounds

rust
pub fn notify<T: Summary + Display>(item: &T) {
    println!("Breaking news! {}", item.summarize());
    println!("Breaking news! {}", item);
}

fn main() {
    // --snip--

    notify(&tweet);
    notify(&article);
}
  • T: Summary + Display{:rust} specifies that T{:rust} must implement both the Summary{:rust} and Display{:rust} traits

Where Clauses

  • Specifing multiple trait bounds could hinder code readablity, like
rust
fn some_function<T: Display + Clone, U : Clone + Debug>(t: &T, u: & U) -> i32 {}
  • where{:rust} clause is used to specify trait bounds, which makes the function signature more readable
rust
pub fn notify<T>(item: &T)
where T: Summary + Display,
      U: Clone + Debug
{
    println!("Breaking news! {}", item.summarize());
    println!("Breaking news! {}", item);
}

Returning Types that Implement Traits

rust
fn returns_summarizable() -> impl Summary {
    Tweet {
        username: String::from("@johndoe"),
        content: String::from("Hello, World !"),
        reply: false,
        retweet: false,
    }
}

fn main() {
    let tweet = returns_summarizable();
    println!("1 new tweet: {}", tweet.summarize());
}
Out · output
$ cargo run

1 new tweet: @johndoe, by Hello, World !
  • impl Summary{:rust} is used as a return type, which specifies that the function will return a type that implements the Summary{:rust} trait

Conditional Implement Methods

  • Methods can be implemented conditionally based on trait bounds
rust
use std::fmt::Display;

struct Pair<T> {
    x: T,
    y: T,
}

impl<T> Pair<T> {
    fn new(x: T, y: T) -> Self {
        Self { x, y }
    }
}

impl<T: Display + PartialOrd> Pair<T> {
    fn cmp_display(&self) {
        if self.x >= self.y {
            println!("The largest member is x = {}", self.x);
        } else {
            println!("The largest member is y = {}", self.y);
        }
    }
}

fn main() {
    let pair = Pair::new(5, 10);
    pair.cmp_display();
}
  • PartialOrd{:rust} and Display{:rust} traits are implemented for the Pair{:rust} struct, which allows the cmp_display{:rust} method to be called

Blanket Implementations

  • Implementing a trait for any type that implements another trait
rust
impl<T: Display> ToString for T {
    fn to_string(&self) -> String {
        format!("{}", self)
    }
}