Deref Coercion
What is Deref
Coercion?
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.
When the Deref
Coercion is applied?
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 typeU
(e.g.,&str
).
As long as
T
implementsDeref<Target=U>
, the compiler will automatically dereference the&T
reference to get a reference to the underlyingU
value.
This allows you to use types like
String
interchangeably with&str
in many situations becauseString
implementsDeref<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 typeT
to a function or method that expects a mutable reference to a different typeU
.
As long as
T
implementsDerefMut<Target=U>
, the compiler will dereference the&mut T
to provide a mutable reference to the underlyingU
value.
This allows you to use types like
Box<T>
(heap-allocated box) interchangeably with&mut T
in some contexts when necessary (assumingBox<T>
implementsDerefMut<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 typeU
.
Similar to the first case, the condition is that
T
implementsDeref<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 Calls
Deref
with Function & Method CallsUsing the previous example of our custom smart pointer. 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>
implementsDeref<Target=String>
, butsay_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
implementsDeref<Target=str>
, it automatically dereferences again to the&String
to get the underlying string slice (&str
) thatsay_hi
can use.Finally, the
say_hi
function will get the correct string format and printHi, Thomas!
.
DerefMut
for Mutable Dereferencing
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
.
As the previous example, 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.
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 ofname
.Deref
coercion happens becauseMySmartPointer
implementsDerefMut<Target=String>
.The compiler automatically dereferences
name
(which is a&mut MySmartPointer<String>
) usingderef_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 printHi, Ashley!
.
Last updated