Deref and DerefMut
Deref and DerefMut Traits
The Deref and DerefMut traits are fundamental to Rust's smart pointer pattern. They allow your custom types to behave like references, enabling automatic dereferencing through the * operator and enabling deref coercion - one of Rust's most convenient ergonomic features.
When you implement Deref for a type, you're telling Rust how to convert a reference to your type into a reference to another type. This is what allows Box<T>, Rc<T>, Arc<T>, and String to seamlessly work with functions expecting references to their inner types.
Deref Coercion
Deref coercion is a compile-time convenience that automatically converts references when types implement Deref. For example:
&Stringcan be used where&stris expected&Box<T>can be used where&Tis expected&Vec<T>can be used where&[T]is expected
This happens automatically in function arguments, method calls, and other contexts where Rust needs to match types.
Your Task
Implement wrapper types that demonstrate Deref and DerefMut patterns:
-
MyBox<T>: A simple wrapper type that implementsDerefandDerefMut, allowing access to the inner value. -
CachedValue<T>: A wrapper that holds a value and tracks how many times it has been accessed (via deref). It should:- Implement
Deref<Target = T>to provide read access while incrementing an access counter - Provide a method
access_count(&self) -> usizeto retrieve the count - Note: Due to
Derefrequiring&self, you'll need interior mutability (Cell)
- Implement
-
NonEmptyVec<T>: A wrapper aroundVec<T>that guarantees at least one element. It should:- Have a constructor
new(first: T) -> Self - Have a method
push(&mut self, value: T) - Implement
Deref<Target = [T]>for slice operations - Implement
DerefMutfor mutable slice operations
- Have a constructor
-
UppercaseString: A string wrapper that always stores its content in uppercase. It should:- Have
new(s: &str) -> Selfthat converts to uppercase - Implement
Deref<Target = str>for string operations - Do NOT implement
DerefMut(to prevent bypassing the uppercase invariant)
- Have
-
Function
describe_length: A generic function demonstrating deref coercion:rust pub fn describe_length<T: Deref<Target = str>>( s: &T ) -> StringThis should work with
&String,&Box<str>,&UppercaseString, etc., returning a description like"Length: 5".
Examples
use deref_derefmut::*;
// MyBox usage
let mut b = MyBox::new(42);
assert_eq!(*b, 42);
*b = 100;
assert_eq!(*b, 100);
// CachedValue usage
let cached = CachedValue::new("hello");
assert_eq!(cached.access_count(), 0);
let _ = cached.len(); // Deref to &str, increments counter
assert_eq!(cached.access_count(), 1);
// NonEmptyVec usage - guaranteed non-empty
let mut nev = NonEmptyVec::new(1);
nev.push(2);
nev.push(3);
assert_eq!(nev.len(), 3); // Deref to &[T]
assert_eq!(nev.first(), Some(&1));
nev[0] = 10; // DerefMut to &mut [T]
assert_eq!(nev[0], 10);
// UppercaseString usage
let upper = UppercaseString::new("hello");
assert_eq!(&*upper, "HELLO");
assert!(upper.starts_with("HE")); // Deref coercion to &str
// describe_length with different types
let s = String::from("hello");
assert_eq!(describe_length(&s), "Length: 5");
let boxed: Box<str> = "world".into();
assert_eq!(describe_length(&boxed), "Length: 5");Hints
Click here to reveal hints
-
The
Dereftrait requires implementing:rust type Target = T; fn deref(&self) -> &Self::Target { ... } -
DerefMutrequiresDerefto be implemented first, and adds:rust fn deref_mut(&mut self) -> &mut Self::Target { ... } -
For
CachedValue, usestd::cell::Cell<usize>to track accesses sincedereftakes&self -
For
NonEmptyVec, you can deref to&[T]by callingas_slice()on the innerVec -
Remember that
DerefMutshould NOT be implemented if it would violate type invariants (likeUppercaseString) -
Deref coercion works through multiple levels:
&MyBox<String>can coerce to&str
Run to execute your code and see test results here.