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”
&andrefare 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