Traits: Defining Shared Behavior

In this chapter, we'll explore define shared behavior with traits that types can implement.

Traits: Defining Shared Behavior

A trait defines functionality a type has and can share with other types. We use traits to define shared behavior abstractly.

Defining a Trait

trait Summary {
    fn summarize(self) -> string
}

Implementing a Trait

struct NewsArticle {
    headline: string,
    location: string,
    author: string,
    content: string,
}
 
impl Summary for NewsArticle {
    fn summarize(self) -> string {
        return self.headline + ", by " + self.author + " (" + self.location + ")"
    }
}
 
struct Tweet {
    username: string,
    content: string,
}
 
impl Summary for Tweet {
    fn summarize(self) -> string {
        return self.username + ": " + self.content
    }
}

Using the trait:

let tweet = Tweet {
    username: "horse_ebooks",
    content: "of course, as you probably already know, people",
}
 
println("1 new tweet: ", tweet.summarize())

Default Implementations

trait Summary {
    fn summarize(self) -> string {
        return "(Read more...)"
    }
}
 
impl Summary for NewsArticle {}  // Uses default

Defaults can call other trait methods:

trait Summary {
    fn summarize_author(self) -> string
 
    fn summarize(self) -> string {
        return "(Read more from " + self.summarize_author() + "...)"
    }
}

Traits as Parameters

fn notify(item: impl Summary) -> void {
    println("Breaking news! ", item.summarize())
}

Or with trait bound syntax:

generic<T> where T: Summary
fn notify(item: T) -> void {
    println("Breaking news! ", item.summarize())
}

Multiple Trait Bounds

fn notify(item: impl Summary + Display) -> void { }
 
// Or:
generic<T> where T: Summary + Display
fn notify(item: T) -> void { }

Returning Traits

fn returns_summarizable() -> impl Summary {
    return Tweet {
        username: "horse_ebooks",
        content: "of course, as you probably already know",
    }
}

Conditionally Implementing Methods

generic<T>
struct Pair {
    x: T,
    y: T,
}
 
generic<T> where T: Display + Ord
impl Pair<T> {
    fn cmp_display(self) -> void {
        if self.x >= self.y {
            println("Largest is x = ", self.x)
        } else {
            println("Largest is y = ", self.y)
        }
    }
}

Continue to Validating References with Lifetimes.