From The Rust Programming Language book:
Deref coercion converts a reference to a type that implements the
Dereftrait into reference to another type
Questions in code snippet below:
Why
&is required forderefto be implicitly called, isn'tmalready a reference?hello(m.deref().deref())works without & operatorMyBox<String> -> String -> &strconvert is happening underneath:- if I add
&in front of convert sequence - that would be&MyBox<String> -> &String -> &&str, why&&is folded in final case (e.g.&&str -> &strwhenhello(&m)is called)?
- if I add
Why I cannot use
hello(m)instead, without&for passingm?
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"));
// Why `&` is required for deref to be implicitly called,
// isn't m already a reference?
hello(&m);
// code below works without & operator
// MyBox<String> -> String -> &str convert is happening here
hello(m.deref().deref());
// why I cannot use the code like one below,
// without & for passing m?, e.g.
// hello(m);
}
Explanation by compiler for hello(m):
Compiling
error[E0308]: mismatched types
--> src/bin/tmp3.rs:38:11
|
38 | hello(m);
| ----- ^ expected `&str`, found `MyBox<String>`
| |
| arguments to this function are incorrect
|
= note: expected reference `&str`
found struct `MyBox<String>`
note: function defined here
--> src/bin/tmp3.rs:19:4
|
19 | fn hello(name: &str) {
| ^^^^^ ----------
help: consider borrowing here
|
38 | hello(&m);
| +
For more information about this error, try `rustc --explain E0308`.
error: could not compile `luhn` (bin "tmp3") due to previous error
Isn't m already borrowed when passed in hello(m)?
You've got the first chain types wrong it's not
MyBox<String>->String->&strbutMyBox<String>->&String->&str, that works because calling a method automatically inserts the necesary reference.But from the list of coercion types you can see only:
is supported,
Tto&UwhereTimplementsDeref<U>orTto&Tare simply not amongst the valid coercion types.So in conclusion the compiler never coerces an owned value to a reference, but coercion from references to other ones is done automatically when the right traits are implemented.
The only time the compiler will insert borrows is when using the method syntax on the
selfparameter, anywhere else only coercion can happen.