Deref Coercion
Last updated
Last updated
Deref
Coercion?π‘ The Deref
trait enables "Deref
coercion," which allows the compiler to automatically perform implicit dereferencing when calling functions or methods by converting the references of custom types to references of their inner types.
This is how Deref
coercion works behind the scenes:
The compiler will check if the argument type implements Deref
.
If it does, and the dereferenced type matches the expected type in the function signature, the compiler will automatically inserts calls to the deref
method as needed.
Deref
Coercion is applied?Rust performs Deref
coercion in three specific cases:
From &T
to &U
when T
: Deref<Target=U>
This happens when you pass a reference to a type T
(e.g., &String
) to a function or method that expects a reference to a different type U
(e.g., &str
).
As long as T
implements Deref<Target=U>
, the compiler will automatically dereference the &T
reference to get a reference to the underlying U
value.
This allows you to use types like String
interchangeably with &str
in many situations because String
implements Deref<Target=str>
.
From &mut T
to &mut U
when T
: DerefMut<Target=U>
This case is similar to the first one, but it applies to mutable references (&mut T
).
Deref
coercion occurs when you pass a mutable reference to a type T
to a function or method that expects a mutable reference to a different type U
.
As long as T
implements DerefMut<Target=U>
, the compiler will dereference the &mut T
to provide a mutable reference to the underlying U
value.
This allows you to use types like Box<T>
(heap-allocated box) interchangeably with &mut T
in some contexts when necessary (assuming Box<T>
implements DerefMut<Target=T>
).
From &mut T
to &U
when T
: Deref<Target=U>
This case is less common, but it's still valid.
It allows dereferencing a mutable reference to a type T
to get an immutable reference to a type U
.
Similar to the first case, the condition is that T
implements Deref<Target=U>
. This can be useful in specific scenarios where you might need a temporary immutable reference from a mutable reference.
Deref
with Function & Method CallsUsing the . To demonstrate how the Deref
coercion works, we add a new function say_hi
which receives a &str
reference.
In this code, the Deref
coercion happens in the say_hi
function.
The say_hi
function expects a &str
reference. But we passed &name
, which is a reference to a MySmartPointer<String>
.
Deref
coercion comes into play again:
The compiler sees the argument type &MySmartPointer<String>
and the expected type &str
.
MySmartPointer<String>
implements Deref<Target=String>
, but say_hi
needs &str
Behind the scenes, the compiler performs a double dereference.
First, it dereferences &name
to get a reference &String
from inner &MySmartPointer<String>
.
Then, because String
implements Deref<Target=str>
, it automatically dereferences again to the &String
to get the underlying string slice (&str
) that say_hi
can use.
Finally, the say_hi
function will get the correct string format and print Hi, Thomas!
.
DerefMut
for Mutable DereferencingRust also provides the DerefMut
trait for mutable dereferencing.
Letβs dive a bit inside the Deref
implementation
DerefMut
trait inherits from the Deref
trait, it means it requires everything from Deref
and adds its own method.
The different here is the DerefMut
has a required method which is called deref_mut
. This method takes &mut self
(a mutable reference to the implementing type) as an argument and returns a mutable reference (&mut
) to the associated type Target
.
To allow dereference mutable reference for our smart pointer, weβre going to implement DerefMut
trait for MySmartPointer
. The deref_mut
method returns a mutable reference (&mut
) to the inner value (&self.0
- the .0
accesses the first value in a tuple struct). This allows dereferencing and mutating to the underlying data.
In the main function, we created a new mutable MySmartPointer
with the string βThomasβ.
The DerefMut
coercion happens in the name = String::from("Ashley")
line.
Weβre assigning a new String
("Ashley") to the dereferenced value of name
.
Deref
coercion happens because MySmartPointer
implements DerefMut<Target=String>
.
The compiler automatically dereferences name
(which is a &mut MySmartPointer<String>
) using deref_mut
to get a mutable reference (&mut String
) to the inner value, and then modifies the inner string through assignment *name
.
Finally, the say_hi
function will print Hi, Ashley!
.
As the , we have the MySmartPointer
smart pointer with implemented Deref
trait. In this updates, we will implement the DerefMut
trait for MySmartPointer
to demonstrate how we can dereference a mutable reference and mutate the data.