fn main() {
let x = 5;
let y = &x;
assert_eq!(5, x);
assert_eq!(5, y);
}
From the bookComparing a number and a reference to a number isn’t allowed because they’re different types. We must use the dereference operator to follow the reference to the value it’s pointing to.Read in context
Memoryderef-operator
Compare let y = &x; with let y = Box::new(x); where x is 5. What does y point to in each case?
From the bookThe main difference between Listing 15-7 and Listing 15-6 is that here we set y to be an instance of a box pointing to a copied value of x rather than a reference pointing to the value of x.Read in context
Codederef-trait
What happens when you compile this code?
struct MyBox<T>(T);
impl<T> MyBox<T> {
fn new(x: T) -> MyBox<T> {
MyBox(x)
}
}
fn main() {
let x = 5;
let y = MyBox::new(x);
assert_eq!(5, x);
assert_eq!(5, *y);
}
From the bookOur MyBox<T> type can’t be dereferenced because we haven’t implemented that ability on our type. To enable dereferencing with the * operator, we implement the Deref trait.Read in context
Codederef-trait
Which body for deref makes this compile and the assertion pass?
use std::ops::Deref;
struct MyBox<T>(T);
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
// ???
}
}
fn main() {
let y = MyBox(5);
assert_eq!(5, *y);
}
From the bookWe fill in the body of the deref method with &self.0 so that deref returns a reference to the value we want to access with the * operatorRead in context
Codederef-trait
y is a MyBox<i32> that implements Deref. When you write *y, what code does Rust actually run?
From the bookWhen we entered *y in Listing 15-9, behind the scenes Rust actually ran this code: *(y.deref())Read in context
Interviewderef-trait
An interviewer asks: "Why does deref return a reference instead of the inner value itself?"
From the bookIf the deref method returned the value directly instead of a reference to the value, the value would be moved out of self. We don’t want to take ownership of the inner value inside MyBox<T> in this case or in most cases where we use the dereference operator.Read in context
Codederef-coercion
MyBox<T> is defined with Deref as shown. What happens when you run this program?
use std::ops::Deref;
struct MyBox<T>(T);
impl<T> MyBox<T> {
fn new(x: T) -> MyBox<T> {
MyBox(x)
}
}
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
fn hello(name: &str) {
println!("Hello, {name}!");
}
fn main() {
let m = MyBox::new(String::from("Rust"));
hello(&m);
}
From the bookBecause we implemented the Deref trait on MyBox<T> in Listing 15-10, Rust can turn &MyBox<String> into &String by calling deref. The standard library provides an implementation of Deref on String that returns a string slice, and this is in the API documentation for Deref. Rust calls deref again to turn the &String into &str, which matches the hello function’s definition.Read in context
Codederef-coercion
m is a MyBox<String> and hello takes name: &str. If Rust had no deref coercion, which call would you have to write?
From the bookThe (*m) dereferences the MyBox<String> into a String. Then, the & and [..] take a string slice of the String that is equal to the whole string to match the signature of hello.Read in context
Interviewderef-coercion
An interviewer asks: "Does deref coercion cost anything at runtime?"
From the bookThe number of times that Deref::deref needs to be inserted is resolved at compile time, so there is no runtime penalty for taking advantage of deref coercion!Read in context
Recallderef-mutChoose TWO
Which TWO are deref coercions Rust performs?
From the bookFrom &T to &U when T: Deref<Target=U> / From &mut T to &mut U when T: DerefMut<Target=U> / From &mut T to &U when T: Deref<Target=U>Read in context
Codederef-mut
Which call does NOT compile?
fn hello(name: &str) {
println!("Hello, {name}!");
}
fn takes_mut(name: &mut String) {}
fn main() {
let mut s = String::from("Rust");
// which call goes here?
}
From the bookRust will also coerce a mutable reference to an immutable one. But the reverse is not possible: Immutable references will never coerce to mutable references.Read in context
Interviewderef-mut
An interviewer asks: "Why can Rust turn a &mut T into a &T, but never a &T into a &mut T?"
From the bookConverting one mutable reference to one immutable reference will never break the borrowing rules. Converting an immutable reference to a mutable reference would require that the initial immutable reference is the only immutable reference to that data, but the borrowing rules don’t guarantee that.Read in context