Deref<T>
- Deref<T> trait is used to customize the behavior of dereference operator (*).
- If we implement the Deref<T> trait, then the smart pointer can be treated as a reference. Therefore, the code that works on the references can also be used on the smart pointers too.
Regular References
Regular reference is a kind of pointer that points to some value which is stored somewhere else. Let’s see a simple example to create the reference of i32 type value and then we use the dereference operator with this reference.
Output:
a and *b are equal
In the above example, a holds the i32 type value, 20 while b contains the reference of ‘a’ variable. If we use *b, then it represents the value, 20. Therefore, we can compare the variable a and *b, and it will return the true value. If we use &b instead of *b, then the compiler throws an error “cannot compare {integer} with {&integer}”.
Box<T> as a Reference
The Box<T> pointer can be used as a reference.
Let’s see a simple example:
Output:
Value of *b is 11
In the above example, Box<T> behaves similarly as the regular references. The only difference between them is that b contains the box pointing to the data rather than referring to the value by using the ‘&’ operator.
Smart Pointer as References
Now, we create the smart pointer similar to the Box<T> type, and we will see how they behave differently from the regular references.
- The Box<T> can be defined as the tuple struct with one element for example, MyBox<T>.
- After creating the tuple struct, we define the function on type MyBox<T>.
Let’s see a simple example:
Output:
In the above example, we create the smart pointer, b, but it cannot be dereferenced. Therefore, we conclude that the customized pointers which are similar to the Box<T> type cannot be dereferenced.
Implementing a Deref Trait
- The Deref trait is defined in the standard library which is used to implement the method named deref.
- The deref method borrows the self and returns a reference to the inner data.
Let’s see a simple example:
Output:
10
Program Explanation
- The Deref trait is implemented on the MyBox type.
- The Deref trait implements the deref() method, and the deref() method returns the reference of ‘a’ variable.
- The type Target = T; is an associated type for a Deref trait. Associated type is used to declare the generic type parameter.
- We create the instance of MyBox type, b.
- The deref() method is called by using the instance of MyBox type, b.deref() and then the reference which is returned from the deref() method is dereferenced.
Deref Coercion
- Deref Coercion is a process of converting the reference that implements the Deref trait into the reference that Deref can convert the original type into.
- Deref Coercion is performed on the arguments of the functions and methods.
- Deref Coercion happens automatically when we pass the reference of a particular type to a function that does not match with the type of an argument in the function definition.
Let’s see a simple example:
Output:
5
In the above example, we are calling the print(&b) function with an argument &b, which is the reference of &Box<i32>. In this case, we implement the Deref trait that converts the &Box<i32> into &i32 through the process of Deref Coercion.
Interaction of Derif Coercion with mutability
Till now, we use the Deref Trait to override the * operator on immutable references, and we can use the DerefMut trait to override the * operator on mutable references.
Rust performs Deref coercion in the following three cases:
- When T: Deref<Target = U> where T and U are the immutable references , then &T is converted into &U type.
- When T: DerefMut<Target = U> where T and U are the mutable references, then &mut T is converted into &mut U.
- When T: Deref<Target = U> where T is a mutable reference and U is an immutable reference, then &mut T is converted into &U.