在函数参数中,使用ref关键字和使用&符号有什么区别?

时间:2019-01-21 07:58:57

标签: rust

在此代码中,sref1sref2s的地址,并且地址相同。 ref&有什么区别?

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中的

f1f2也是字符串的地址,f2将拥有所有权,但是f2打印的地址不是字符串的地址。与f1打印的地址相同。为什么?

3 个答案:

答案 0 :(得分:4)

在模式中,&破坏借项的结构,ref绑定到按引用而非按值的位置。

换句话说,&可以帮助您进行借阅,ref说“借用我匹配的东西到这个地方”

  

&ref是相反的。

#![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>() })
}

输出将如下所示:

&bool
bool
&&bool

答案 1 :(得分:3)

&适用于右值(类型),而ref适用于左值(变量名称),但是它们都具有相同的作用。

ref在模式内非常有用,因为您只能访问左值:

#![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 => (),
    }
}

但是,今天,此关键字并没有真正有用,因为模式匹配更加“巧妙”。它了解到,如果您借用匹配的值,则意味着您要借用内部值:

match &opt {
    Some(i) => print_type(i), // &i32
    None => (),
}

答案 2 :(得分:3)

  

在函数参数中,使用ref关键字和使用&符号之间有什么区别?

您已经回答了自己的问题

  

[使用ref]将获得所有权

将变量的所有权转移到函数,然后获取对已移动变量的引用。也就是说,

fn f2(ref _s: String) {}

等效于

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

如果您使用&Stringwhich you shouldn't),则该函数不拥有该变量的所有权,而仅是对其的引用。

  

打印的地址[...]不相同

是,因为变量已移动。当变量移动时,其所在的地址可能会更改。这就是为什么它被称为“移动”。

另请参阅: