6

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?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
iDuanYingJie
  • 663
  • 4
  • 11

3 Answers3

6

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”

& and ref 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
Akiner Alkan
  • 6,145
  • 3
  • 32
  • 68
  • For further info you can check the following links. , [rust-book](https://doc.rust-lang.org/rust-by-example/scope/borrow/ref.html) , [rust-users](https://users.rust-lang.org/t/when-to-ref-or/5798) , [reddit-ref keyword](https://www.reddit.com/r/rust/comments/2tq33x/ref_keyword/) – Akiner Alkan Jan 21 '19 at 08:37
3

& 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 => (),
}
Boiethios
  • 38,438
  • 19
  • 134
  • 183
  • *because the pattern matching is more "clever"* — more clever, yes, but not completely. I've found myself needing to use `ref` when I did not expect to. – Shepmaster Jan 21 '19 at 14:21
3

In function parameters, what is the difference between using the ref keyword and using the & symbol?

You've already answered your own question:

[using ref] will take ownership

Ownership of the variable is transferred to the function and then a reference to the moved variable is taken. That is,

fn f2(ref _s: String) {}

is equivalent to

fn f2(s0: String) {
    let _s = &s0;
    // or 
    // let ref _s = s0;
}

If you use &String (which you shouldn't), the function doesn't take ownership of the variable, only a reference to it.

the address printed [...] is not the same

Yes, because the variable has been moved. When a variable moves, the address it is located at might change. That's why it's called "moving".

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366