Rust 模式匹配中的& 和 ref

一、Rust & 和 ref

1.Rust的ref有什么用

根据Rust官方文档https://doc.rust-lang.org/std/keyword.ref.html

Rust ref 主要用在模式匹配match的所有权问题中。

ref在 Rust中,也是声明一个指针类型变量,进一步说明ref和&在其它方面区别,我们下一篇再说。

Rust的模式匹配,可以发生在函数参数match

  1. 函数参数
fn foo(x: String) {//String::from("test")的所有权已经移交给了x
  println!("{}",x);
  // 代码
}

fn main() {
    let mut s=String::from("test");
    foo(s);
    println!("{}",s);//s的所有权已经丢失,所以不能使用了,此处出错
}

特别注意一下,函数传参也会交出所有权
2.match

fn main() {
    let x = String::from("test");

    match x {
        y => println!("{}", y),// String::from("test")的所有权移动给了y
        _ => println!("Default case, x = {:?}", x),
    }

    println!("at the end: x = {:?}", x);//x的所有权已经丢失,不能再使用。
}

特别注意一下,match的模式匹配是会交出所有权的。

除了使用&引用借用来避免交出所有权的问题,在模式匹配中,我们可以使用**&或ref**来避免交出所有权,match中的ref不再遵循借用规则。那么前面的代码我们可以修改为。

  1. 函数参数使用**&避免**交出所有权
fn foo(x: &mut String) {//
  println!("{}",x);
  // 代码
}

fn main() {
    let mut s=String::from("test");
    foo(&mut s);//(可变/不可变)引用,不拥有所有权
    println!("{}",s);
}

代码运行通过

    Finished release [optimized] target(s) in 0.20s
     Running `target/release/world_hello`
test
test

2、match使用ref避免交出所有权

fn main() {
    let x = String::from("test");

    match x {
        ref y => println!("{}", y),// 其实在match中,不是定义一个变量,而是声明一个变量,ref是进一步声明,y是一个引用,但是不能够&y,因为我们不能够在match中声明y的具体类型。
        _ => println!("Default case, x = {:?}", x),
    }

    println!("at the end: x = {:?}", x);
}

代码运行通过

    Finished release [optimized] target(s) in 0.20s
     Running `target/release/world_hello`
test
test

其实这里你可能会问,为什么在match中,不使用&借用避免所有权移动的问题,这是因为match本身机制导致的。

在match中,我们没有机会声明变量类型,不能用&修饰匹配的变量

当然,你非要在**match使用&**来避免移交所有权的问题,我们可以这样做

fn main() {
  let x = String::from("test");

  match &x {//将引用定义在这里
      y => println!("{}", y),//这里不能够写成&y => println!("{}", y),
      _ => println!("Default case, x = {:?}", x),
  }

  println!("at the end: x = {:?}", x);
}

代码运行也是成功的

    Finished release [optimized] target(s) in 0.22s
     Running `target/release/world_hello`
test
at the end: x = "test"

我们再来看一个骚的


// 修复错误,尽量少地修改代码
// 不要移除任何代码行
fn main() {
    let mut v = String::from("hello,");
    let r = &mut v;

    match r {
       &mut value => value.push_str(" world!") 
    }
}

前面我们说了 ,我们不能声明匹配变量,也就是value,那么**&mut 是肯定不能用**的,其实第一版修改,我们可以改成


// 修复错误,尽量少地修改代码
// 不要移除任何代码行
fn main() {
  let mut v = String::from("hello,");
  let r = &mut v;

  match r {
     value => value.push_str(" world!") //这样其实value就是可变引用,但是&mut v本身的所有权被value拿走了
  }
}

根据代码注释,如果我们稍加修改就会发现问题


// 修复错误,尽量少地修改代码
// 不要移除任何代码行
fn main() {
  let mut v = String::from("hello,");
  let r = &mut v;

  match r {
     value => value.push_str(" world!") 
  }
  println!("{}",r);
}

运行代码

error[E0382]: borrow of moved value: `r`
  --> src/main.rs:11:17
   |
6  |   let r = &mut v;
   |       - move occurs because `r` has type `&mut String`, which does not implement the `Copy` trait
...
9  |      value => value.push_str(" world!") 
   |      ----- value moved here
10 |   }
11 |   println!("{}",r);
   |                 ^ value borrowed here after move

这里说了,&mut v的所有权被value拿走了

那我不想被value拿走,我们应该怎么做,那么这时候ref的作用就来了,我们可以这么修改



// 修复错误,尽量少地修改代码
// 不要移除任何代码行
fn main() {
  let mut v = String::from("hello,");
  let r = &mut v;

  match *r {//注意这里是*r,因为r本身就是&str,如果传下去r,ref r 就变成了双重引用,不符合题意
     ref mut value => value.push_str(" world!") //此时value就是&str类型,但是这不是引用类型
  }
  println!("{}",r);
}

运行代码

    Finished release [optimized] target(s) in 0.34s
     Running `target/release/world_hello`
hello, world!

前面我们说了,ref不遵循借用的那一套规则,所以上面的代码是可以运行成功的。

按照正常思路的话(假设),按道理应该是两个可变引用,是违背借用原则的,会不会是match{}框住了value的作用域导致,其实只有一个可变引用?

那我们在看一段代码


// 修复错误,尽量少地修改代码
// 不要移除任何代码行
fn main() {
  let mut v = String::from("hello,");
  let r = &mut v;

  match *r {
     ref mut value => {
      value.push_str(" world!") ;
      println!("{}",r);
    }
  }
  println!("{}",r);
}

运行一下

    Finished release [optimized] target(s) in 0.21s
     Running `target/release/world_hello`
hello, world!
hello, world!

哈哈,我们已经验证完了

ref不遵循借用的那一套规则,在match的模式匹配中,ref也可以是不拿所有权的一种引用方法。

相关推荐

  1. Rust 模式匹配& ref

    2024-04-23 01:16:02       14 阅读
  2. Rust-08-枚举模式匹配

    2024-04-23 01:16:02       7 阅读
  3. vue ref $refs使用

    2024-04-23 01:16:02       36 阅读
  4. Rust---模式(Pattern)匹配

    2024-04-23 01:16:02       13 阅读
  5. 学习 Rust 第十天:枚举模式匹配

    2024-04-23 01:16:02       12 阅读
  6. Rust---模式匹配之matchif let

    2024-04-23 01:16:02       12 阅读
  7. Rustif let语法:更简洁模式匹配

    2024-04-23 01:16:02       26 阅读
  8. 深入Rust模式匹配与枚举类型

    2024-04-23 01:16:02       34 阅读
  9. vue3reactiveref

    2024-04-23 01:16:02       5 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-23 01:16:02       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-23 01:16:02       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-23 01:16:02       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-23 01:16:02       18 阅读

热门阅读

  1. RedisHttpSession反序列化UID问题跟踪

    2024-04-23 01:16:02       14 阅读
  2. 【Git】git revert 命令(撤销 commit 改动)

    2024-04-23 01:16:02       22 阅读
  3. 深度学习概念

    2024-04-23 01:16:02       12 阅读
  4. AJAX请求(axios篇)

    2024-04-23 01:16:02       14 阅读
  5. UDF小白入门

    2024-04-23 01:16:02       14 阅读
  6. git工具的安装及使用

    2024-04-23 01:16:02       12 阅读
  7. backtracking Leetcode 回溯算法题

    2024-04-23 01:16:02       11 阅读
  8. Linux文本处理三剑客:awk、grep和sed

    2024-04-23 01:16:02       13 阅读