Traits
Defining a trait
Traits define shared behavior (like interfaces in C#). Types implement traits to provide that behavior.
trait Greet {
fn greet(&self) -> String;
}In C#: Like an interface: interface IGreet { string Greet(); }.
Implementing a trait
struct Person { name: String }
impl Greet for Person {
fn greet(&self) -> String {
format!("Hello, I'm {}", self.name)
}
}In C#: Like class Person : IGreet { ... }. In Rust you can implement a trait for a type in any crate (your type or the trait must be in your crate).
Trait bounds
Use traits to constrain generic types:
fn print_greet<T: Greet>(x: &T) {
println!("{}", x.greet());
}In C#: Like void PrintGreet<T>(T x) where T : IGreet.
Default implementations
Traits can provide default method bodies; implementors can override them:
trait Greet {
fn greet(&self) -> String {
String::from("Hi!")
}
}In C#: Like default interface members in C# 8+.
derive
The compiler can auto-implement some traits for your types:
#[derive(Debug, Clone, PartialEq)]
struct Point { x: i32, y: i32 }In C#: Like code generators or source generators that implement interfaces; Rust’s derive is built-in for common traits.
Key takeaway
Traits are the main abstraction mechanism (like interfaces). Use impl Trait for Type to implement; use T: Trait in generics to constrain. derive generates common implementations.