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