trait MyTrait{
fn show(self);
}
impl MyTrait for i32{
fn show(self) {
//todo!()
println!("i32");
}
}
fn main(){
let i = 0;
let rf = &i;
rf.show(); // print i32
}
Invoking the method show on the reference(whose type is &i32) is ok. However, Don't I implement MyTrait merely for type i32, why it works on the type &i32? IMO, i32 and &i32 are different types. Then, we continually add an implementation, such that the code will be
trait MyTrait{
fn show(self);
}
impl MyTrait for i32{
fn show(self) {
//todo!()
println!("i32");
}
}
impl MyTrait for &i32{
fn show(self) {
//todo!()
println!("&i32");
}
}
fn main() {
let i = 0;
let rf = &i;
rf.show(); // print &i32
i.show(); // print i32
}
Compare with the first example, the invocation of rf.show now prints &i32, which exactly matches the type of the implementation(i.e. &i32).
So, what are the rules here when we invoke a method of a trait on an entity? How does it match? Does it first match the type of entity with the type on which the trait is implemented? Or something else?
The rules are described here. An exact type match on the receiver will take precedence, but there can also be an autoref or (multiple levels of) autoderef, et cetera.
rf.show(); is desugared to <&i32 as MyTrait>::show(rf) because the receiver type &i32 has this method.
Similarly i.show(); is desugared to <i32 as MyTrait>::show(i).
The rule is for a type T, the candidate types are
T
&T
&mut T
*T
&*T
&mut *T
coercion to U
&U
&mut U
The order is important.
And inherent methods are prior to trait methods.
That is to say, the type of receiver(i.e. the type of self) is the principle to determine whether the expression could match the method or not, Right? In other words, we first build a set of types that are sourced from transforming the type of the expression on which the method is called, then we just match each element of the set to the type of receiver of the found methods.
The first step for me is: desugar self / &self / &mut self and desugar Self
impl &Type {
fn f(self) {} // self: Self means self: &Type, so this method is for `&Type` directly
}
impl Type {
fn f(&self) {} // self: &Self means self: &Type, so this method is for `&Type` directly, too
}