Structs

The impl Block

An impl (implementation) block associates methods, associated functions, and associated constants with a nominal type (such as a struct or enum), or implements a trait for a type.

Two Forms of impl Blocks

Rust supports two distinct forms of impl blocks:

  1. Inherent impl block (impl Type { ... }): Defines methods and associated functions that belong directly to Type without involving any trait.
  2. Trait impl block (impl Trait for Type { ... }): Implements the required items of Trait for Type.
Anatomy of Inherent and Trait `impl` Blocks:

  impl<'a, T: Clone> Container<'a, T> {       <-- Inherent impl (declares generic params after `impl`)
      pub const VERSION: u32 = 1;             <-- Associated constant
      pub fn new(slice: &'a [T]) -> Self {..} <-- Associated function (no `self`)
      pub fn len(&self) -> usize {..}         <-- Method (`&self`)
  }

  impl<'a, T: fmt::Display> fmt::Display for Container<'a, T> { <-- Trait impl
      fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {..}
  }
use std::fmt;

struct Temperature {
    celsius: f64,
}

// 1. Inherent implementation block
impl Temperature {
    const ABSOLUTE_ZERO_C: f64 = -273.15;

    fn from_celsius(celsius: f64) -> Self {
        assert!(celsius >= Self::ABSOLUTE_ZERO_C, "Below absolute zero");
        Self { celsius }
    }

    fn to_fahrenheit(&self) -> f64 {
        (self.celsius * 9.0 / 5.0) + 32.0
    }
}

// 2. Trait implementation block
impl fmt::Display for Temperature {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:.1}°C ({:.1}°F)", self.celsius, self.to_fahrenheit())
    }
}

fn main() {
    let boiling = Temperature::from_celsius(100.0);
    println!("Water boils at {boiling}");
}
Water boils at 100.0°C (212.0°F)

Generic and Lifetime Parameters on impl Blocks

When a struct has lifetime or type parameters (struct SliceWindow<'a, T>), the impl keyword must first declare those parameters (impl<'a, T>) so they are in scope for the target type SliceWindow<'a, T>:

Syntax Meaning
impl<'a, T> Window<'a, T> Implements methods for every lifetime 'a and every type T
impl<'a, T: Ord> Window<'a, T> Implements methods only when T implements Ord
impl<'a> Window<'a, f64> Implements specialized methods only when the element type is f64
struct Window<'a, T> {
    items: &'a [T],
}

// Available for ALL types `T`
impl<'a, T> Window<'a, T> {
    fn new(items: &'a [T]) -> Self {
        Self { items }
    }

    fn len(&self) -> usize {
        self.items.len()
    }
}

// Available ONLY when `T` is `f64`
impl<'a> Window<'a, f64> {
    fn sum(&self) -> f64 {
        self.items.iter().copied().sum()
    }
}

fn main() {
    let names = ["alpha", "beta"];
    let w_str = Window::new(&names);
    println!("w_str len = {}", w_str.len());

    let floats = [1.5, 2.5, 3.0];
    let w_f64 = Window::new(&floats);
    println!("w_f64 len = {}, sum = {}", w_f64.len(), w_f64.sum());
}
w_str len = 2
w_f64 len = 3, sum = 7

Coherence Rule for Inherent impl Blocks (E0116)

You can only write an inherent impl Type block inside the same crate that defines Type (though the impl block can be placed in any submodule of that crate). Attempting to add inherent methods directly to a foreign type such as Vec<T> or i32 fails with E0116:

// ❌ does not compile
impl i32 {
    fn double(&self) -> i32 {
        *self * 2
    }
}

fn main() {}
error[E0116]: cannot define inherent `impl` for a type outside of the crate where the type is defined
 --> src/main.rs:1:1
  |
1 | impl i32 {
  | ^^^^^^^^ impl for type defined outside of crate
  |
  = note: define and implement a trait or new type instead

To add custom methods to a type from another crate, either wrap it in a newtype struct (struct MyInt(i32);) or define a local extension trait (trait DoubleExt { fn double(&self) -> Self; }) and implement that trait for i32.