As the title says, traits are Rust’s alternative to Interfaces. They allow us to use polymorphism in Rust. We can create a trait like this:

1
2
3
trait Calculator {
    fn add(&self, left: i32, right: i32) -> i32;
}

To implement the trait we use the impl keyword on a struct:

1
2
3
4
5
6
7
struct GoodCalculator {}

impl Calculator for GoodCalculator {
    fn add(&self, left: i32, right: i32) -> i32 {
        left + right
    }
}

Traits (like interfaces) are useful as function parameters, so different types can be passed. The simplest way to receive a trait as a parameter is using the impl keyword like this:

1
2
3
fn add_using_calculator(calculator: &impl Calculator) {
    println!("The result of adding {} and {} is: {}", 10, 5, calculator.add(10, 5));
}

When we need a type to implement multiple interfaces, we can use this syntax:

1
2
3
4
fn add_and_print(the_thing: &(impl Calculator + Printer)) {
    the_thing.print();
    println!("The result of adding {} and {} is: {}", 10, 5, the_thing.add(10, 5));
}

Another syntax:

1
2
3
4
fn add_and_print<T: Calculator + Printer>(the_thing: &T) {
    the_thing.print();
    println!("The result of adding {} and {} is: {}", 10, 5, the_thing.add(10, 5));
}

When we have multiple arguments using the following syntax is preferred:

1
2
3
4
5
6
7
fn add_and_print<T>(the_thing: &T)
where
    T: Calculator + Printer
{
    the_thing.print();
    println!("The result of adding {} and {} is: {}", 10, 5, the_thing.add(10, 5));
}

Abstract methods / Default implementations

Sometimes we want to provide default implementations for some methods on our traits. This can easily be done:

1
2
3
4
5
trait SoundMaker {
    fn print(&self) {
        println!("Default implementation")
    }
}

Conclusion

Traits in Rust, work similarly to interfaces in Golang. I added some code using the above examples to Github so you can see it in action.

[ programming  rust  ]
Error Handling in Rust
Sending E-mails From Rust With Brevo
Asynchronous Programming with Tokio
Programming Concurrency in Rust
Smart Pointers in Rust