Traits
## Learning Objectives
- Define and implement traits
- Use trait bounds
- Default implementations
- Master common standard traits
- Work with generictraits
## What are Traits?
Traits define shared behavior across types:
```rust
trait Summary {
fn summarize(&self) -> String;
}
```
## Implementing Traits
### Basic Implementation
```rust
trait Summary {
fn summarize(&self) -> String;
}
struct Article {
title: String,
author: String,
}
impl Summary for Article {
fn summarize(&self) -> String {
format!("{} by {}", self.title, self.author)
}
}
fn main() {
let article = Article {
title: String::from("Rust Tutorial"),
author: String::from("Alice"),
};
println!("{}", article.summarize());
}
```
### Multiple Traits
```rust
trait Summarize {
fn summarize(&self) -> String;
}
trait Printable {
fn print(&self);
}
struct Article {
title: String,
author: String,
}
impl Summarize for Article {
fn summarize(&self) -> String {
format!("{} by {}", self.title, self.author)
}
}
impl Printable for Article {
fn print(&self) {
println!("Title: {}\nAuthor: {}", self.title, self.author);
}
}
```
## Default Implementations
```rust
trait Summary {
fn summarize(&self) -> String {
String::from("(Read more...)") // Default implementation
}
}
struct Tweet {
username: String,
content: String,
}
impl Summary for Tweet {
// Uses default summarize implementation
// Or override:
// fn summarize(&self) -> String {
// format!("@{}: {}", self.username, self.content)
// }
}
fn main() {
let tweet = Tweet {
username: String::from("alice"),
content: String::from("Hello world"),
};
println!("{}", tweet.summarize()); // (Read more...)
}
```
## Trait Bounds
### Basic Syntax
```rust
fn notify(item: &impl Summary) {
println!("Breaking news! {}", item.summarize());
}
```
### Trait Bound Syntax
```rust
fn notify(item: &T) {
println!("Breaking news! {}", item.summarize());
}
```
### Multiple Trait Bounds
```rust
fn notify(item: &(impl Summary + Display)) { }
fn notify(item: &T) { }
```
### where Clauses
```rust
fn some_function(t: &T, u: &U)
where
T: Display + Clone,
U: Clone + Debug,
{
// ...
}
```
## Conditionally Implement Methods
```rust
use std::fmt::Display;
struct Pair {
x: T,
y: T,
}
impl Pair {
fn new(x: T, y: T) -> Self {
Self { x, y }
}
}
impl Pair {
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);
}
}
}
```
## Returning Types that Implement Traits
```rust
trait Summary {
fn summarize(&self) -> String;
}
fn returns_summarizable() -> impl Summary {
Tweet {
username: String::from("alice"),
content: String::from("Hello"),
}
}
```
## Using Trait Bounds for Conditional Methods
```rust
use std::fmt::Display;
struct Wrapper {
value: T,
}
impl Wrapper {
fn new(value: T) -> Self {
Wrapper { value }
}
}
impl Wrapper {
fn print(&self) {
println!("{}", self.value);
}
}
impl Wrapper {
fn eq(&self, other: &Wrapper) -> bool {
self.value == other.value
}
}
```
## Common Standard Traits
### Debug
```rust
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
fn main() {
let rect = Rectangle { width: 30, height: 50 };
println!("{:?}", rect);
println!("{:#?}", rect);
}
```
### Clone and Copy
```rust
#[derive(Clone, Copy)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let p1 = Point { x: 1, y: 2 };
let p2 = p1; // Copy
let p3 = p1.clone(); // Clone
println!("{:?}", p1); // p1 still valid (Copy)
}
```
### PartialEq and Eq
```rust
#[derive(PartialEq, Eq)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let p1 = Point { x: 1, y: 2 };
let p2 = Point { x: 1, y: 2 };
println!("{}", p1 == p2); // true
}
```
### PartialOrd and Ord
```rust
#[derive(PartialOrd, Ord)]
struct Person {
name: String,
age: u32,
}
fn main() {
let p1 = Person { name: "Alice".to_string(), age: 30 };
let p2 = Person { name: "Bob".to_string(), age: 25 };
println!("{}", p1 > p2); // true
}
```
### Display
```rust
use std::fmt;
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)
}
}
fn main() {
let p = Point { x: 1, y: 2 };
println!("{}", p); // (1, 2)
}
```
### Default
```rust
#[derive(Default)]
struct Config {
width: u32,
height: u32,
name: String,
}
fn main() {
let config = Config {
width: 100,
..Default::default()
};
}
```
## Blanket Implementations
Implement trait for all types that satisfy bounds:
```rust
use std::fmt::Display;
impl T {
fn print_twice(&self) {
println!("{}", self);
println!("{}", self);
}
}
fn main() {
42.print_twice();
}
```
## Supertraits
Require a trait to implement another trait:
```rust
use std::fmt::{Display, Debug};
trait OutlinePrint: Display {
fn outline_print(&self) {
let output = self.to_string();
let len = output.len();
println!("{}", "*".repeat(len + 4));
println!("* {} *", " ".repeat(len));
println!("* {} *", output);
println!("* {} *", " ".repeat(len));
println!("{}", "*".repeat(len + 4));
}
}
struct Point {
x: i32,
y: i32,
}
impl Display for Point {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
impl OutlinePrint for Point {}
```
## Summary
- Traits define shared behavior (like interfaces)
- Implement traits with `impl TraitName for Type`
- Default implementations can be overridden
- Trait bounds: `impl Trait` or `T: Trait`
- Multiple bounds: `T: Trait1 + Trait2`
- where clauses for complex bounds
- `impl Trait` for return types
- Common derive traits: Debug, Clone, Copy, PartialEq, Eq, Default
- Blanket implementations: `impl Trait for T`
Comments
Comments powered by Giscus
To enable comments, add your Giscus embed code here.
Learn more about Giscus →