As stated in Rustonomicon, Dot operator
in Rush does a lot of magics for you. Namely, those are auto-referencing
, auto-dereferencing
, coercion
UNTIL types match.
This becomes really powerful when you implement Deref
trait or the kind.
For example, suppose we have the following structs:
struct Wrapped;
struct Wrapper1(Wrapped);
struct Wrapper2(Wrapper1);
Just to stay on the point, I created two fairly simple tuple structs and a unit-like one. And let’s implement Deref
trait on both Wrapper1
and Wrapper2
as follows:
impl Deref for Wrapper2{
type Target = Wrapper1;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Deref for Wrapper1{
type Target = Wrapped;
fn deref(&self) -> &Self::Target {
&self.0
}
}
Lastly, let’s implement method on each structs:
impl Wrapper2{
fn from_wrapper2(&self){
println!("Wrapper2")
}
}
impl Wrapper1{
fn from_wrapper1(&self){
println!("Wrapper1")
}
}
impl Wrapped{
fn from_wrapped(&self){
println!("Wrapped")
}
}
In the main function, let’s create Wrapper2
object wrapping Wrapper1
that will also wrap Wrapped
:
fn main (){
let test = Wrapper2(Wrapper1(Wrapped));
At this point, what will happen if you put dot(.) after test? That is to say, what will appear in your IDE? The answer is you have an access to all of the methods implemented above!
fn main (){
let test = Wrapper2(Wrapper1(Wrapped));
test.from_wrapper2(); // Ok
test.from_wrapper1(); // Ok
test.from_wrapped(); // Ok
}
I feel like being able to call all of three methods from test variable rather creates confusion. Anyone who accesses the test variable which is an instance of Wrapper2 struct would actually expect to call a method from a Wrapper2 struct not from a Wrapper1 or Wrapped. What would be the possible use case for this functionality? And I guess you wouldn't be able to do the same (calling methods via automatic dereferencing) if you do not implement Deref for the wrapper structs?
And an automatic type casting is definitely a life saver as it removes so much of unnecessary explicit type casting.