Implementing Deref for smart pointers makes accessing the data behind them convenient, which is why they implement Deref. On the other hand, the rules regarding Deref and DerefMut were designed specifically to accommodate smart pointers. Because of this, Deref should only be implemented for smart pointers to avoid confusion.
I understand its usefulness,but I don't know what's the use of this blanket implementation of the Deref trait.
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_deref", issue = "88955")]
impl<T: ?Sized> const Deref for &T {
type Target = T;
#[rustc_diagnostic_item = "noop_method_deref"]
fn deref(&self) -> &T {
*self
}
}
As the book says here https://doc.rust-lang.org/book/ch15-02-deref.html#treating-a-type-like-a-reference-by-implementing-the-deref-trait
Without the Deref trait, the compiler can only dereference & references. The deref method gives the compiler the ability to take a value of any type that implements Deref and call the deref method to get a & reference that it knows how to dereference.
Why do we need this blanket implementation of Deref trait for &T type if the compiler knows how to deference it?
What are Rust's exact auto-dereferencing rules? this question does not answer my question, because my question is what is the use of this blanket implementation.
Why is the return type of Deref::deref itself a reference? this question didn't solve my doubts either. in the first answer the author did not explain why there is the blanket implementation of Deref trait for &T type.
I added the code from the author of the first answer, with my own modifications
Rust playground https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=25387e87ea7a7ef349df9e9b6671f6e7
I added some comments to make sure I really got it
use std::ops::Deref;
use std::rc::Rc;
fn foo<T: Deref<Target = i32>>(t: T) {
println!("{}", *t);
print_type_of(&t);
print_type_of(&(*t));
println!("-----------------");
}
fn main() {
// Ok, because &i32 implements Deref<Target = i32>, so deref() return &i32 and the compiler can deref it again to get i32
// Thanks to the blanket implementation
foo(&100i32);
// No, because &&i32.deref() return &&i32, so the compiler can't deref it twice to get i32
foo(&&100i32);
// Ok, because Box<i32> implements Deref<Target = i32>, so deref() return &i32 and the compiler can deref it again to get i32
// But this has nothing to do with the blanket implementation of Deref for &T
// Because Box is not a reference type
foo(Box::new(42i32));
// Ok, because Rc<i32> implements Deref<Target = i32>, so deref() return &i32 and the compiler can deref it again to get i32
foo(Rc::new(5i32));
}
fn print_type_of<T>(_: &T) {
println!("{}", std::any::type_name::<T>())
}
I'm not sure I understand your answer
A Deref implementation exists for &T the same reason any trait exists: genericism.
Even if the compiler knows how to dereference references innately because they are built-in to the language, the Deref implementation should still exist so &T can be used in a context that requires Deref. Consider this function:
fn foo<T: Deref<Target = i32>>(t: T) {
println!("{}", *t);
}
See it working on the playground;
It can accept references, Boxs, Rcs, etc. If the Deref implementation did not exist for references, then you could use the dereferencing operator * on it directly, but you could not pass it to this function that dereferences what is passed. That would be inconsistent and confusing for no reason.
I'm not sure what your example is supposed to prove; it can't be compiled outside the standard library and your assessment of the types is incorrect (Self is &T so self is of type &&T, which when dereferenced returns a &T, which matches the return type). Implementing an equivalent trait works just fine:
trait Deref {
type Target: ?Sized;
fn deref(&self) -> &Self::Target;
}
impl<T: ?Sized> Deref for &T {
type Target = T;
fn deref(&self) -> &T {
*self
}
}
See it working on the playground;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With