Rust - OOP Features

Traits

It is allowed for different traits to have method definitions with same signatures and also these traits may be implements on the same struct. Moreover, this struct can implement method with same signature on it's impl block.

trait Pilot {
    fn fly(&self);
}

trait Wizard {
    fn fly(&self);
}

struct Human;

impl Pilot for Human {
    fn fly(&self) {
        println!("This is your captain speaking.");
    }
}

impl Wizard for Human {
    fn fly(&self) {
        println!("Up!");
    }
}

impl Human {
    fn fly(&self) {
        println!("*waving arms furiously*");
    }
}

When we try to create Human and run fly method, own Human's implementation will be called:

fn main() {
    let person = Human;
    person.fly();
}
// will print: "*waving arms furiously*"

If we need to run implementation of fly from specific trait, we need to call it explicitly:

fn main() {
    let person = Human;
    Pilot::fly(&person);
    Wizard::fly(&person);
    person.fly();
}

Supertraits

Supertraits allow to inherit functionality from another traits. For example:

use std::fmt;

trait OutlinePrint: fmt::Display {
    fn outline_print(&self) {
        let output = self.to_string();
        let len = output.len();
        println!("{}", "*".repeat(len + 4));
        println!("*{}*", " ".repeat(len + 2));
        println!("* {} *", output);
        println!("*{}*", " ".repeat(len + 2));
        println!("{}", "*".repeat(len + 4));
    }
}

OutlinePrint extends functionality of fmt::Display trait so it is possible to use self.to_string inside of it's methods.

But we still need to implement fmt::Display to make it work:

struct Point {
    x: i32,
    y: i32,
}

impl OutlinePrint for Point {}

use std::fmt;

impl fmt::Display for Point {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

References