题外话:关键词ref与引用符&

  在下面一段代码只有一个let语句里,目的是说明该&ref操作等价于什么也没有做,它们是相反的操作,类似于操作*&也是相反的操作。


# #![allow(unused_variables)]
#fn main() {
    // File: lib-hello/src/immut/type_ref/mod.rs
    // Function use_ref_and()

    let x: u8 = 33;
    let w: &u8 = &x;
    let ref y: u8 = x;
    let z: &u8 = y;
    
    println!("x = {:p}", &x);
    println!("w = {:p}", w);
    println!("y = {:p}", y);
    println!("z = {:p}", z);

    println!("x = {}", x);
    println!("w = {}", w);
    println!("y = {}", y);
    println!("z = {}", z);

    let &ref y  = &x;
    println!("y = {:p}", y);
    println!("y = {}", y);
    println!();
    
    let x: Vec<u8> = vec![33, 42];
    let w: &Vec<u8> = &x;
    let ref y: Vec<u8> = x;
    let z: &Vec<u8> = y;
    
    println!("x = {:p}", &x);
    println!("w = {:p}", w);
    println!("y = {:p}", y);
    println!("z = {:p}", z);

    println!("x = {:?}", x);
    println!("w = {:?}", w);
    println!("y = {:?}", y);
    println!("z = {:?}", z);

    let &ref y  = &x;
    println!("y = {:p}", y);
    println!("y = {:?}", y);

#}

  借助于工具cargo-clippy,使用下面命令:

# 工具cargo-clippy命令
cargo clippy

可以获取如下编译器的警告信息:

warning: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead
   --> lib-hello/src/immut/type_ref/mod.rs:105:9
    |
105 |     let ref y: u8 = x;
    |     ----^^^^^--------- help: try: `let y: &u8 = &x;`
    |
    = note: `#[warn(clippy::toplevel_ref_arg)]` on by default
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#toplevel_ref_arg

  从上面警告,可以解读这些内容:

  • 在上面程序一段代码包括四个let语句里,中间两个是等价的;
  • 不鼓励在整个let语句上使用关键词引用符ref,而应使用借用符
  • 从中可以知道,关键词ref不应该在let语句上使用,而更适合在macth语句里使用它。借用符要引用一个对象,而ref通过引用而不是按值绑定到位置。换句话说,借用符实现简单的借用,而引用符ref则是“借用我,到与我相匹配的位置上去”;

  在宏println!()打印内存地址信息时,只有非引用对象变量,才在变量前面使用借用符&。要是去掉该引用符&,编译器将会出现下面错误信息,从中也可以知道,谁是引用谁不是引用对象:

error[E0277]: the trait bound `u8: std::fmt::Pointer` is not satisfied
 --> src/main.rs:5:26
  |
5 |     println!("x = {:p}", x);
  |                          ^ the trait `std::fmt::Pointer` is not implemented for `u8`
  |
  = note: required by `std::fmt::Pointer::fmt`

参考资料