Traits
-
Allows sharing methods.
-
Polymorphism is done via Traits + Generics.
-
"Similar to Interfaces in other languages".
-
Complex example of using Traits to constrain accepted implementation types .
-
Around ~{10:00} shows the final part of the code.
-
Implementing a Trait for a Struct
-
The functions inside the Trait may have no implementation or a default implementation that can be overridden by the implementing type.
pub trait Summary {
fn summarize(&self) -> String;
}
pub struct NewsArticle {
pub headline: String,
pub location: String,
pub author: String,
pub content: String,
}
pub struct Tweet {
pub username: String,
pub content: String,
pub reply: bool,
pub retweet: bool,
}
impl Summary for NewsArticle {
fn summarize(&self) -> String {
format!("{}, by {} ({})", self.headline, self.author, self.location)
}
}
impl Summary for Tweet {
fn summarize(&self) -> String {
format!("{}: {}", self.username, self.content)
}
}
Traits as types and Trait Bounds
-
Ex1 : "Accepts anything that implements Summary".
// Syntax sugar for the version below. pub fn notify(item: &impl Summary) { println!("Breaking news! {}", item.summarize()); } // Same thing, represented via a "trait bound". pub fn notify<T: Summary>(item: &T) { println!("Breaking news! {}", item.summarize()); } -
Ex2 :
pub fn notify(item1: &impl Summary, item2: &impl Summary) { } // Same thing, but the "trait bound" infers directly that the types of 'item1' and 'item2' must be the same. pub fn notify<T: Summary>(item1: &T, item2: &T) { } -
Ex3 :
pub fn notify(item: &(impl Summary + Display)) { } // Same thing, but using "trait bound". pub fn notify<T: Summary + Display>(item: &T) { } -
Ex4 : Use of
where, with the sole purpose of avoiding a very long signature.
fn some_function<T: Display + Clone, U: Clone + Debug>(t: &T, u: &U) -> i32 {
}
// Same thing.
fn some_function<T, U>(t: &T, u: &U) -> i32
where
T: Display + Clone,
U: Clone + Debug,
{
Differences between Traits and Abstract Classes in C#
-
Multiple inheritance :
-
Traits in Rust allow multiple implementations . A type can implement several traits, while in C#, a class can only directly inherit from one abstract class (but can implement multiple interfaces).
-
-
No class hierarchy :
-
Rust has no class hierarchy. Traits are independent from each other and are not part of an inheritance structure like abstract classes in C#. This avoids the rigidity of single inheritance found in C#.
-
-
No state or fields :
-
Traits in Rust cannot contain fields (state) , while abstract classes in C# can. Traits define only behavior, without storing data.
-
-
Implementing traits for external types :
-
In Rust, you can implement traits for types defined outside your control (provided you defined the trait or the type). This is not allowed with abstract classes in C#.
-
-
Generics vs. dynamic typing :
-
Traits in Rust often use generics to determine behavior at compile time. In C#, polymorphism via abstract classes is often based on dynamic typing at runtime.
-