Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

rust

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?

like image 520
iDuanYingJie Avatar asked Jan 21 '19 07:01

iDuanYingJie


Video Answer


2 Answers

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
like image 128
Akiner Alkan Avatar answered Nov 15 '22 10:11

Akiner Alkan


& 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 => (),
}
like image 41
Boiethios Avatar answered Nov 15 '22 11:11

Boiethios