Method Resolution and Borrowing
This is where the magic happens for your daily coding. When you call a method:
Rust tries to find the method on the type itself.
If it fails, it tries to dereference the type (
*t) and looks again.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:
Identity:
receiver(The type matches exactly).Autoref:
&receiver(Rust borrows it for you).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.