Traits
Using traits to define shared behavior.
Traits
Traits allow us to define shared behavior that different types can implement.
Trait Definition
RUSTtrait Summary { fn summarize(&self) -> String; }
Trait Implementation
RUSTstruct NewsArticle { headline: String, location: String, author: String, content: String, } impl Summary for NewsArticle { fn summarize(&self) -> String { format!("{}, by {} ({})", self.headline, self.author, self.location) } }
Default Implementation
RUSTtrait Summary { fn summarize(&self) -> String { String::from("(Read more...)") } }
Trait Parameters
RUSTfn notify(item: &impl Summary) { println!("Breaking news! {}", item.summarize()); }
Trait Bound Syntax
RUSTfn notify<T: Summary>(item: &T) { println!("Breaking news! {}", item.summarize()); }
Multiple Trait Bounds
RUSTfn some_function<T: Display + Clone, U: Clone + Debug>(t: &T, u: &U) -> i32 { // ... }
where Clause
RUSTfn some_function<T, U>(t: &T, u: &U) -> i32 where T: Display + Clone, U: Clone + Debug, { // ... }
Code Examples
Basic Trait
Trait definition and implementation
trait Summary {
fn summarize(&self) -> String;
}
struct NewsArticle {
headline: String,
author: String,
}
impl Summary for NewsArticle {
fn summarize(&self) -> String {
format!("{}, by {}", self.headline, self.author)
}
}
fn main() {
let article = NewsArticle {
headline: String::from("Rust new version"),
author: String::from("John"),
};
println!("{}", article.summarize());
}Explanation:
A trait defines shared behavior. impl Summary for NewsArticle implements the trait for the NewsArticle type. Now NewsArticle can use the summarize() method.
Default Implementation
Trait with default methods
trait Summary {
fn summarize(&self) -> String {
String::from("(Read more...)")
}
fn summarize_author(&self) -> String;
}
struct Tweet {
username: String,
content: String,
}
impl Summary for Tweet {
fn summarize_author(&self) -> String {
format!("@{}", self.username)
}
}
fn main() {
let tweet = Tweet {
username: String::from("rust_lang"),
content: String::from("Rust 1.70 released!"),
};
println!("{}", tweet.summarize());
println!("{}", tweet.summarize_author());
}Explanation:
Trait methods can have default implementations. If a type doesn't implement it explicitly, it uses the default version.
Trait Parameters
Functions with trait parameters
trait Summary {
fn summarize(&self) -> String;
}
struct NewsArticle {
headline: String,
}
impl Summary for NewsArticle {
fn summarize(&self) -> String {
self.headline.clone()
}
}
fn notify(item: &impl Summary) {
println!("Breaking news! {}", item.summarize());
}
fn notify2<T: Summary>(item: &T) {
println!("Breaking news! {}", item.summarize());
}
fn main() {
let article = NewsArticle {
headline: String::from("Rust news"),
};
notify(&article);
notify2(&article);
}Explanation:
The &impl Summary parameter accepts any type that implements the Summary trait. This enables polymorphism.
Blockchain: Validatable Trait
Using traits for blockchain validation
trait Validatable {
fn validate(&self) -> bool;
fn get_id(&self) -> String;
}
struct Transaction {
id: String,
amount: u64,
fee: u64,
}
struct Block {
id: String,
previous_hash: String,
hash: String,
}
impl Validatable for Transaction {
fn validate(&self) -> bool {
self.amount > 0 && self.fee >= 10
}
fn get_id(&self) -> String {
self.id.clone()
}
}
impl Validatable for Block {
fn validate(&self) -> bool {
!self.hash.is_empty() && !self.previous_hash.is_empty()
}
fn get_id(&self) -> String {
self.id.clone()
}
}
fn process_validatable<T: Validatable>(item: &T) {
if item.validate() {
println!("{} is valid", item.get_id());
} else {
println!("{} is invalid", item.get_id());
}
}
fn main() {
let tx = Transaction {
id: String::from("tx1"),
amount: 100,
fee: 10,
};
let block = Block {
id: String::from("block1"),
previous_hash: String::from("prev"),
hash: String::from("hash"),
};
process_validatable(&tx);
process_validatable(&block);
}Explanation:
Traits enable polymorphism in blockchain code. Different types (transactions, blocks) can implement the same trait, allowing generic validation functions. This is essential for blockchain architecture.
Exercises
Trait Implementation
Create a Drawable trait and implement it on a struct!
Starter Code:
fn main() {
let circle = Circle { radius: 5.0 };
circle.draw();
}