Interfaces in Rust

Interfaces in Rust are implemented using traits. Traits define a set of methods that a type must implement.

use std::f64::consts::PI;

// Here's a basic trait for geometric shapes.
trait Geometry {
    fn area(&self) -> f64;
    fn perimeter(&self) -> f64;
}

// For our example we'll implement this trait on
// `Rectangle` and `Circle` types.
struct Rectangle {
    width: f64,
    height: f64,
}

struct Circle {
    radius: f64,
}

// To implement a trait in Rust, we use the `impl` keyword.
// Here we implement `Geometry` for `Rectangle`.
impl Geometry for Rectangle {
    fn area(&self) -> f64 {
        self.width * self.height
    }

    fn perimeter(&self) -> f64 {
        2.0 * (self.width + self.height)
    }
}

// The implementation for `Circle`.
impl Geometry for Circle {
    fn area(&self) -> f64 {
        PI * self.radius * self.radius
    }

    fn perimeter(&self) -> f64 {
        2.0 * PI * self.radius
    }
}

// If a function takes a trait object, then we can call
// methods that are in the named trait. Here's a
// generic `measure` function taking advantage of this
// to work on any `Geometry`.
fn measure(g: &dyn Geometry) {
    println!("Area: {}", g.area());
    println!("Perimeter: {}", g.perimeter());
}

fn main() {
    let r = Rectangle { width: 3.0, height: 4.0 };
    let c = Circle { radius: 5.0 };

    // The `Rectangle` and `Circle` types both
    // implement the `Geometry` trait so we can use
    // instances of these types as arguments to `measure`.
    measure(&r);
    measure(&c);
}

To run the program:

$ rustc interfaces.rs
$ ./interfaces
Area: 12
Perimeter: 14
Area: 78.53981633974483
Perimeter: 31.41592653589793

In Rust, traits are used to define shared behavior in an abstract way, similar to interfaces in other languages. They allow us to constrain generic type parameters to types that implement a specific set of methods.

To learn more about Rust’s traits, check out the Rust Book chapter on Traits.