I write a simple program in Rust. This program can compile.
use std::cell::{Ref, RefCell};
fn print_number(x: &i32) {
println!("x is {}", x);
}
fn main() {
let stack: i32 = 42;
let reference: &i32 = &stack;
let refcell: RefCell<&i32> = RefCell::new(reference);
let wrapped: Ref<'_, &i32> = refcell.borrow();
print_number(&wrapped);
print_number(*wrapped);
}
I can tell the reason why both work:
&
works, because &wrapped
is of type &Ref<&i32>
, which can be deref-coerced to &&i32
, which can be deref-coerced to &i32
.*
works, because *wrapped
is equivalent to *Deref::deref(&wrapped)
. We know Deref::deref(&Ref<&i32>)
results to &&i32
, so *Deref::deref(&Ref<&i32>)
results to *&&i32
, i.e., &i32
.It seems that the 2nd approach (with *
) is more straight-forward, however the Rust compiler suggests me using the 1st approach (with &
). If I add one line:
print_number(wrapped);
This of course can't compile. But I'm interested with the compiler report:
error[E0308]: mismatched types
--> src/main.rs:16:18
|
16 | print_number(wrapped);
| ------------ ^^^^^^^ expected `&i32`, found `Ref<'_, &i32>`
| |
| arguments to this function are incorrect
|
= note: expected reference `&i32`
found struct `Ref<'_, &i32>`
note: function defined here
--> src/main.rs:3:4
|
3 | fn print_number(x: &i32) {
| ^^^^^^^^^^^^ -------
help: consider borrowing here
|
16 | print_number(&wrapped);
| +
For more information about this error, try `rustc --explain E0308`.
error: could not compile `testrust` (bin "testrust") due to 1 previous error
In the report's "help", it suggests me adding a &
. I'm wondering why it doesn't suggest me adding a *
.
Recommending &
fixes the code for any type T
in Ref<'_, T>
, while *
only works if the contained type implements Copy
and is a reference. Copy
is needed because else you couldn't "move" out of the Ref
and a reference because your function requires it's argument to be one. Special casing "T
is a shared reference" (that includes is Copy
as shared references always are) doesn't seem all that useful if the other, and already necessary to implement for some cases, way of recommending &
also works and produces the same assembly.
In other words recommending *
over &
here requires additional code (= more work) for no ergonomics or performance gain whatsoever.