Traits

https://doc.rust-lang.org/reference/items/traits.html

Traits denote common behavior types can have (compare with interfaces in other languages):

#![allow(unused)]
fn main() {
trait DoubleSelf {
    fn double_self(&mut self);
}
}

You can implement:

  • one of your traits on anyone's type
  • anyone's trait on one of your types
  • but not a foreign trait on a foreign type

Implementing foreign traits on foreign types is called creating "orphan instances", and is generally considered a bad thing.

Here's an implementation of our trait on a type:

#![allow(unused)]
fn main() {
impl DoubleSelf for i32 {
    fn double_self(&mut self) {
        self = self * 2;
    }
}
}

The Rust standard library has a couple traits that don't have any methods, these are called "marker traits" and usually denote some features of a type. For example:

  • Copy means "use copy semantics on instances of this type" (like C language)
  • Send means "this type is safe to send to another thread"

Trait methods can also take self by reference or mutable reference:

#![allow(unused)]
fn main() {
// the clone trait explicitly creates a copy of an instance from reference
impl Clone for Point {
    fn clone(&self) -> Self {
        Self { self.x, self.y } // floats are copy so we can use that
    }
}
}

The dot syntax implicitly borrows self where applicable so that you don't have to do things like (&self).my_method().

Some common traits can be automatically implemented on your type by using a derive attribute:

#![allow(unused)]
fn main() {
#[derive(Clone, Copy)]
struct MyStruct;
}