In this code, sref1
and sref2
are the addresses of s
, and the addresses are the same. What is the difference between ref
and &
?
fn main() {
let s = String::from("hello");
let sref1 = &s;
let ref sref2 = s;
println!("{:p}", sref1);
println!("{:p}", sref2);
f1(&s);
f2(s);
}
fn f1(_s: &String) {
println!("{:p}", _s);
}
fn f2(ref _s: String) {
println!("{:p}", _s);
}
_s
in f1
and f2
is also the address of the string, f2
will take ownership, but the address printed by f2
is not the same as the address printed by f1
. Why?
In patterns, &
destructures a borrow, ref
binds to a location by-reference rather than by-value.
In other words, &
lets you reach through a borrow, and ref
says “take a borrow to this place within the thing I’m matching”
&
andref
are opposites.
#![feature(core_intrinsics)]
fn main() {
let x = &false;
print_type_name_of(x);
let &x = &false;
print_type_name_of(x);
let ref x = &false;
print_type_name_of(x);
}
fn print_type_name_of<T>(_: T) {
println!("{}", unsafe { std::intrinsics::type_name::<T>() })
}
The output will be like following:
&bool
bool
&&bool
&
applies to the rvalue (the type) while ref
applies to the lvalue (the variable name), but they both do the same thing.
ref
was useful inside a pattern, because you have only access to a lvalue:
#![feature(core_intrinsics)]
fn print_type<T>(_: T) {
println!("{}", unsafe { std::intrinsics::type_name::<T>() })
}
fn main() {
let opt = Some(0);
match opt {
Some(ref i) => print_type(i), // &i32
None => (),
}
}
However, today, this keyword is not really useful, because the pattern matching is more "clever". It understands that if you borrow the matching value, it means that you want to borrow the inner:
match &opt {
Some(i) => print_type(i), // &i32
None => (),
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With