Traits

Implementing Multiple Traits

A single concrete type can implement any number of distinct traits, each in its own dedicated impl Trait for Type block (or via #[derive(...)]), allowing the type to participate in multiple independent subsystems simultaneously.

Composing Orthogonal Capabilities on One Type

Each impl Trait for Type block adds one facet of behavior to the type without coupling the traits to one another:

use std::fmt;

trait Identifiable {
    fn id(&self) -> u64;
}

trait Serializable {
    fn to_wire_bytes(&self) -> Vec<u8>;
}

#[derive(Debug, Clone, PartialEq)]
struct SensorReading {
    sensor_id: u64,
    celsius: i16,
}

impl Identifiable for SensorReading {
    fn id(&self) -> u64 {
        self.sensor_id
    }
}

impl Serializable for SensorReading {
    fn to_wire_bytes(&self) -> Vec<u8> {
        let mut bytes = Vec::with_capacity(10);
        bytes.extend_from_slice(&self.sensor_id.to_be_bytes());
        bytes.extend_from_slice(&self.celsius.to_be_bytes());
        bytes
    }
}

impl fmt::Display for SensorReading {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Sensor #{}: {}°C", self.sensor_id, self.celsius)
    }
}

fn transmit<T: Identifiable + Serializable + fmt::Display>(packet: &T) {
    println!(
        "Transmitting [id={}] ({}) -> {:02x?}",
        packet.id(),
        packet,
        packet.to_wire_bytes()
    );
}

fn main() {
    let reading = SensorReading {
        sensor_id: 7,
        celsius: 23,
    };
    transmit(&reading);
}
Transmitting [id=7] (Sensor #7: 23°C) -> [00, 00, 00, 00, 00, 00, 00, 07, 00, 17]

Resolving Method Name Collisions Across Multiple Traits (E0034)

When a type implements two traits that both define a method with the same name (fn format(&self)) and both traits are in scope, calling value.format() is ambiguous (E0034):

// ❌ does not compile
trait HtmlExport {
    fn export(&self) -> String;
}

trait MarkdownExport {
    fn export(&self) -> String;
}

struct Document(&'static str);

impl HtmlExport for Document {
    fn export(&self) -> String {
        format!("<p>{}</p>", self.0)
    }
}

impl MarkdownExport for Document {
    fn export(&self) -> String {
        format!("**{}**", self.0)
    }
}

fn main() {
    let doc = Document("Hello");
    println!("{}", doc.export());
}
error[E0034]: multiple applicable items in scope
  --> src/main.rs:26:24
   |
26 |     println!("{}", doc.export());
   |                        ^^^^^^ multiple `export` found
   |
note: candidate #1 is defined in an impl of the trait `HtmlExport` for the type `Document`
  --> src/main.rs:13:5
   |
13 |     fn export(&self) -> String {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: candidate #2 is defined in an impl of the trait `MarkdownExport` for the type `Document`
  --> src/main.rs:19:5
   |
19 |     fn export(&self) -> String {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
help: disambiguate the method for candidate #1
   |
26 |     println!("{}", HtmlExport::export(&doc));
   |                    ~~~~~~~~~~~~~~~~~~~~~~~~
help: disambiguate the method for candidate #2
   |
26 |     println!("{}", MarkdownExport::export(&doc));
   |                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Disambiguate the call by naming the desired trait explicitly (HtmlExport::export(&doc) or MarkdownExport::export(&doc)):

trait HtmlExport {
    fn export(&self) -> String;
}

trait MarkdownExport {
    fn export(&self) -> String;
}

struct Document(&'static str);

impl HtmlExport for Document {
    fn export(&self) -> String {
        format!("<p>{}</p>", self.0)
    }
}

impl MarkdownExport for Document {
    fn export(&self) -> String {
        format!("**{}**", self.0)
    }
}

fn main() {
    let doc = Document("Hello");
    println!("HTML:     {}", HtmlExport::export(&doc));
    println!("Markdown: {}", MarkdownExport::export(&doc));
}
HTML:     <p>Hello</p>
Markdown: **Hello**