Conditional Method Implementations

#![allow(unused)]
fn main() {
// No trait bounds on the type definition.
pub struct Value<T>(T);

// Instead bounds are put on the implementations for the type.
impl<T: std::fmt::Display> Value<T> {
    fn log(&self) {
        println!("{}", self.0);
    }
}

// alternatively
impl<T> Value<T> {
    // Specifies the trait bound in a where expression
    fn log_error(&self)
    where
        T: std::error::Error,
    {
        eprintln!("{}", self.0);
    }
}
}
  • When authoring a type with generic parameters, we can write implementations for that type that depend on what the parameters are or what traits they implement.

  • These methods are only available when the type meets those conditions.

  • For things like ordered sets, where you’d want the inner type to always be Ord, this is the preferred way of putting a trait bound on a parameter of a type.

    We don’t put the definition on the type itself as this would cause downstream issues for everywhere the type is mentioned with a generic parameter.

    We can maintain invariants just fine with conditional method implementations.