@@ -9,51 +9,70 @@ extension method?
99
1010``` rust,editable
1111mod ext {
12- pub trait StrExt {
13- fn trim_ascii (&self) -> &str ;
12+ pub trait CountOnesExt {
13+ fn count_ones (&self) -> u32 ;
1414 }
1515
16- impl StrExt for String {
17- fn trim_ascii(&self) -> &str {
18- self.trim_start_matches(|c: char| c.is_ascii_whitespace())
16+ impl CountOnesExt for i32 {
17+ fn count_ones(&self) -> u32 {
18+ let value = *self;
19+ (0..32).filter(|i| ((value >> i) & 1i32) == 1).count() as u32
1920 }
2021 }
2122}
2223fn main() {
23- pub use ext::StrExt ;
24- // Which `trim_ascii ` method is invoked?
25- // The one from `StrExt `? Or the inherent one from `str `?
26- assert_eq!(String::from(" dad ").trim_ascii (), "dad" );
24+ pub use ext::CountOnesExt ;
25+ // Which `count_ones ` method is invoked?
26+ // The one from `CountOnesExt `? Or the inherent one from `i32 `?
27+ assert_eq!((-1i32).count_ones (), 32 );
2728}
2829```
2930
3031<details >
3132
32- - The foreign type may, in a newer version, add a new inherent method with the
33+ - A foreign type may, in a newer version, add a new inherent method with the
3334 same name as our extension method.
3435
3536 Ask: What will happen in the example above? Will there be a compiler error?
3637 Will one of the two methods be given higher priority? Which one?
3738
38- Add a ` panic!("Extension trait") ` in the body of ` StrExt::trim_ascii ` to
39- clarify which method is being invoked.
39+ Add a ` panic!("Extension trait"); ` in the body of ` CountOnesExt::count_ones `
40+ to clarify which method is being invoked.
4041
41- - [ Inherent methods have higher priority than trait methods] [ 1 ] , _ if_ they have
42- the same name and the ** same receiver** , e.g., they both expect ` &self ` as
43- input. The situation becomes more nuanced if they use a ** different
44- receiver** , e.g., ` &mut self ` vs ` &self ` .
42+ - To prevent users of the Rust language from having to manually specify which
43+ method to use in all cases, there is a priority ordering system for how
44+ methods get "picked" first:
45+ - Immutable (` &self ` ) first
46+ - Inherent (method defined in the type's ` impl ` block) before Trait (method
47+ added by a trait impl).
48+ - Mutable (` &mut self ` ) Second
49+ - Inherent before Trait.
4550
46- Change the signature of ` StrExt::trim_ascii ` to
47- ` fn trim_ascii(&mut self) -> &str ` and modify the invocation accordingly:
51+ If every method with the same name has different mutability and was either
52+ defined in as an inherent method or trait method, with no overlap, this makes
53+ the job easy for the compiler.
54+
55+ This does introduce some ambiguity for the user, who may be confused as to why
56+ a method they're relying on is not producing expected behavior. Avoid name
57+ conflicts instead of relying on this mechanism if you can.
58+
59+ Demonstrate: Change the signature and implementation of
60+ ` CountOnesExt::count_ones ` to ` fn count_ones(&mut self) -> u32 ` and modify the
61+ invocation accordingly:
4862
4963 ``` rust
50- assert_eq! ((& mut " dad " ) . trim_ascii (), " dad " );
64+ assert_eq! ((& mut - 1 i32 ) . count_ones (), 32 );
5165 ```
5266
53- Now ` StrExt::trim_ascii ` is invoked, rather than the inherent method, since
67+ ` CountOnesExt::count_ones ` is invoked, rather than the inherent method, since
5468 ` &mut self ` has a higher priority than ` &self ` , the one used by the inherent
5569 method.
5670
71+ If an immutable inherent method and a mutable trait method exist for the same
72+ type, we can specify which one to use at the call site by using
73+ ` (&<value>).count_ones() ` to get the immutable (higher priority) method or
74+ ` (&mut <value>).count_ones() `
75+
5776 Point the students to the Rust reference for more information on
5877 [ method resolution] [ 2 ] .
5978
0 commit comments