Associated Functions
An associated function is any function defined inside an impl block for a type. In everyday Rust terminology, the phrase "associated function" refers specifically to functions in an impl block that do not take self as their first parameter and are called using the :: path operator on the type name (Type::function(args)), such as String::new() or Vec::with_capacity(10).
Methods vs. Non-Method Associated Functions
| Feature | Associated Function (no self) |
Method (takes self, &self, or &mut self) |
|---|---|---|
| First parameter | Any parameter (or none) | self, &self, &mut self, self: Box<Self>, etc. |
| Call syntax | Type::func(args) |
instance.method(args) (or Type::method(&instance, args)) |
| Requires an existing instance? | No | Yes |
| Typical use cases | Constructors (new, with_capacity, from_parts), factory helpers, type-level utilities |
Inspecting, mutating, or transforming an existing value |
Defining and Calling Associated Functions
Inside an impl block, Self refers to the implementing type, so refactoring or renaming the struct never requires updating the return type inside its associated functions:
#[derive(Debug)]
struct Matrix2x2 {
data: [[f64; 2]; 2],
}
impl Matrix2x2 {
// Associated function: returns the 2x2 zero matrix
fn zeros() -> Self {
Self {
data: [[0.0, 0.0], [0.0, 0.0]],
}
}
// Associated function: returns the 2x2 identity matrix
fn identity() -> Self {
Self {
data: [[1.0, 0.0], [0.0, 1.0]],
}
}
// Associated function: constructs a diagonal matrix from two values
fn diagonal(d1: f64, d2: f64) -> Self {
Self {
data: [[d1, 0.0], [0.0, d2]],
}
}
// Method (takes `&self`): computes the determinant of an instance
fn determinant(&self) -> f64 {
(self.data[0][0] * self.data[1][1]) - (self.data[0][1] * self.data[1][0])
}
}
fn main() {
let zero = Matrix2x2::zeros();
let id = Matrix2x2::identity();
let scale = Matrix2x2::diagonal(3.0, 4.0);
println!("zero det: {}", zero.determinant());
println!("id det: {}", id.determinant());
println!("scale det: {}", scale.determinant());
}
zero det: 0
id det: 1
scale det: 12
Calling Associated Functions on Generic Types with the Turbofish (::<T>)
When a struct has type parameters (struct Buffer<T>), Rust usually infers T from the arguments or the target variable's type annotation. When T cannot be inferred from context, specify it on the type using Type::<T>::function():
#[derive(Debug)]
struct Pair<T> {
left: T,
right: T,
}
impl<T: Default> Pair<T> {
fn default_pair() -> Self {
Self {
left: T::default(),
right: T::default(),
}
}
}
fn main() {
// Type `i32` inferred from the variable annotation:
let p1: Pair<i32> = Pair::default_pair();
// Type `String` specified explicitly via turbofish `Pair::<String>::default_pair()`:
let p2 = Pair::<String>::default_pair();
println!("p1 = {p1:?}");
println!("p2 = {p2:?}");
}
p1 = Pair { left: 0, right: 0 }
p2 = Pair { left: "", right: "" }
Associated Constants in impl Blocks
In addition to functions and methods, an impl block can define associated constants (const NAME: Type = value;) that are accessed via Type::NAME:
struct HttpPacket;
impl HttpPacket {
const DEFAULT_PORT: u16 = 80;
const MAX_HEADER_BYTES: usize = 8192;
}
fn main() {
println!(
"Default port: {}, max header size: {} bytes",
HttpPacket::DEFAULT_PORT,
HttpPacket::MAX_HEADER_BYTES
);
}
Default port: 80, max header size: 8192 bytes