Apr 20, 2026

[Rust] method resolution

Method Resolution and Borrowing

This is where the magic happens for your daily coding. When you call a method:

  1. Rust tries to find the method on the type itself.

  2. If it fails, it tries to dereference the type (*t) and looks again.

  3. If that fails, it tries to reference the type (&t) and looks again.



The Search Algorithm

Rust looks for a method named method by checking these categories in order:

1. Direct Match (Value and References)

First, it checks the type of the receiver (T) and its immediate references:

  • T (The type itself)

  • &T (Immutable reference)

  • &mut T (Mutable reference)

2. Deref Coercion (The "Unwrapping" Loop)

If no match is found, Rust uses the Deref trait to "unwrap" the type. If T implements Deref<Target = U>, it adds U to the search list and repeats step 1:

  • U

  • &U

  • &mut U

This continues recursively. If U derefs to V, it checks V, &V, &mut V. This is why you can call &str methods on a Box<String>.

3. Unsourced Coercion (Array to Slice)

If the type is an array [T; n], Rust will eventually attempt to coerce it into a slice [T].


The Three Transformation Rules

For every candidate type P found in the search above, Rust tries to match the method signature by attempting these three transformations in this exact order:

  1. Identity: receiver (The type matches exactly).

  2. Autoref: &receiver (Rust borrows it for you).

  3. Autoref-Mut: &mut receiver (Rust borrows it mutably).


Why the order matters

If a type has both an immutable foo(&self) and a mutable foo(&mut self), and you call it on a value, Rust will pick the immutable one first if it satisfies the call. This prevents accidental mutation.


Special Cases & Edge Cases

1. Shadowing (Inherent vs. Trait)

Rust has a strict hierarchy for where the method is defined:

  • Inherent Impls: Methods defined directly on the struct (impl MyStruct { ... }) always win.

  • Trait Impls: Methods from traits only count if the trait is in scope (use path::to::Trait).

  • Collision: If two traits in scope provide the same method name for the same type, the compiler throws an error, and you must use Fully Qualified Syntax: Trait::method(&receiver).

2. The "Dot" vs. "Function" Syntax

The auto-deref/autoref magic only happens with dot notation (a.b()).

If you use the associated function syntax (Type::method(a)), you must provide the exact type expected by the function signature. No coercion will help you there.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.