IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> The Rust Programming Language - 第18章 模式与模式匹配 - 18.3 模式的全部语法 -> 正文阅读

[Java知识库]The Rust Programming Language - 第18章 模式与模式匹配 - 18.3 模式的全部语法

18 模式与模式匹配

模式是Rust中的特殊语法,用来匹配类型中的结构,无论类型复杂与否。模式由以下一些内容组合而成:

字面值\解构的数组、枚举、元组或者结构体\变量\通配符\占位符,这些部分描述了我们需要处理的数据形状。(匹配模式其实可以理解为匹配项,简单理解就是把两个项目拉起来比较,看等不等于,等于的话我们就执行一些代码,不等于的话执行另一些代码。这个点就跟条件语句外加等于号一样,只不过Rust中把它专门做了个匹配模式)

18.3 模式的全部语法

本节中,我们收集了模式中所有有效的语法,并将讨论为什么可能要使用每个语法

匹配字面值

 let x =1;

    match x {
        1 => println!("one"),
        2 => println!("two"),
        3 => println!("three"),
        _ => println!("anything"),
    }
    
        Running `target\debug\model.exe`
one

匹配命名变量

fn main() {
    let x =Some(5);
    let y = 10;

    match x {
        Some(50) => println!("Got 50"),
        Some(y)=>println!("Matched,y = {:?}",y),
        _=> println!("Default case,x = {:?}",x)
    }
    println!("at the end: x= {:?}, y = {:?}",x,y)
}
     Running `target\debug\model.exe`
Matched,y = 5
at the end: x= Some(5), y = 10

match语句中引入了一个新的变量y,我们将它与x匹配,其实意思是将x的值赋值给这个内部变量y,这个y和match语法块外的那个y没有关系

多个模式

fn main() {

    let x = 1;
    match x {
        1 | 2=> println!("one or two"),
        3 => println!("three"),
        _ => println!("anything"),
    }
}

通过… = 匹配值的范围

…= 允许我们匹配一个闭区间范围内的值

fn main() {

    let x = 1;
    match x {
        1..=5 => println! ("one through five"),
        _ => println!("something else"),
    }
}
     Running `target\debug\model.exe`
one through five

这种闭区间就比或好多了,尤其是数量比较大的时候,但是范围只允许用数字或者char的值。char和数字值是Rust仅有的可以判断范围是否为空的值

如下是一个使用char类型值范围的例子

fn main() {
    let x = 'c';

    match x {
        'a'..='j' => println!("early ASCII letter"),
        'k'..='z' => println!("late ASCII letter"),
        _ => println!("something else"),
    }
}
early ASCII letter

结构并分解值

也可以使用模式来解构结构体、枚举、元组和引用,以便使用这些值的不同部分

struct Point {
    x:i32,
    y:i32,
}

fn main() {
    let p = Point {x:0,y:7};
 
    let Point {x:a,y:b} = p;
    assert_eq!(0,a);
    assert_eq!(7,b);
 }

使用match语句将point值分为三种情况

fn main() {
    let p = Point {x:0,y:7};

    match p {
        Point{x,y:0} =>println!("on the x axis at {}",x),
        Point{x:0,y} =>println!("on the y axis at {}",y),
        Point{x,y} =>println!("on neither axis:({},{})",x,y),
    }
 }
     Running `target\debug\model.exe`
on the y axis at 7

解构枚举

enum Message {
    Quit,
    Move(i32,i32),
    Write(String),
    ChangeColor(i32,i32,i32),
}

fn main() {
    let msg = Message::ChangeColor(0,160,255);
     
    match msg {
        Message::Quit => {
            println!("the quit varient has no data to destructure")
        }
        Message::Move (x,y) => {
            println!(
                "move in the x direction {} and in the y direction {}",
                x,
                y
            );
        }
        Message::Write(text) => println!("Text meaasge:{}",text),
        Message::ChangeColor(r,g,b) => {
        println!("change the color to red {},green {},and blue {}",
                r,
                g,
                b
            )
        }
    }
 }

上述代码发非常简单和易于理解,解构包含不同类型值成员的枚举

解构嵌套的结构体和枚举

enum Color {
    Rgb(i32,i32,i32),
    Hsv(i32,i32,i32),
}

enum Message {
    Quit,
    Move{x:i32,y:i32},
    Write(String),
    ChangeColor(Color),
}

fn main() {
    let msg = Message::ChangeColor(Color::Hsv(0,160,255));
     
    match msg {
        Message::ChangeColor(Color::Rgb(r, g, b))=>{
            println!("Change the color to red{},green{},and blue{}",
            r,
            g,
            b
          )
        }
        Message::ChangeColor(Color::Hsv(h,s,v))=> {
            println!(
                "change the color to hue {},saturation {},and value {}",
                h,
                s,
                v
            )
        }
        _=> ()
    }
 }
  Running `target\debug\model.exe`
change the color to hue 0,saturation 160,and value 255

匹配嵌套的枚举

解构结构体和元组

甚至可以用复杂的方式来混合、匹配和嵌套结构模式

let  ((feet, inches),Point{x,y}) =((3,10),Point{x:3,y:-10});

通过模式解构是一个方便利用部分值片段的手段,比如结构体中每个单独字段的值

忽略模式中的值

有时候忽略模式中的一些值是有用的,比如match中最后捕获全部情况的分支实际上没有做任何事,但是它确实对所有剩余情况负责

使用 _ 忽略整个值

fn foo(_: i32,y:i32) {
    println!("This code only uses the y parameter: {}",y)
}
fn main() {
    foo(3, 4)
}
     Running `target/debug/model`
This code only uses the y parameter: 4

大部分情况当你不再需要特定的参数时,最好修改签名不再包含无用的参数。在一些情况下忽略函数参数会变的特别有用,比如实现trait时,当你需要特定类型签名但是函数实现并不需要某个参数时,此时编译器就不会警告说存在未使用的函数参数,就跟使用命名参数一样

使用嵌套的 _ 忽略部分值

也可以在一个模式内部使用 _ 忽略部分值,例如,只需要测试部分值但在期望运行的代码中没有用到其他部分时

fn main() {
    let mut setting_value = Some(5);
    let mut new_setting_value = Some(10);

    match (setting_value,new_setting_value) {
        (Some(_),Some(_)) => {
            println!("Can't overwrite an exiting customized value");
        }
        _ => {
            setting_value = new_setting_value;
        }
    }
    println!("setting is {:?}",setting_value)

}
     Running `target/debug/model`
Can't overwrite an exiting customized value
setting is Some(5)
fn main() {
  
    let numbers = (2,4,8,16,32);

    match numbers {
        (first,_,third,_,fifth) => {
            println!("Some numbers: {},{},{}",first,third,fifth)
        },
    }

}
     Running `target/debug/model`
Some numbers: 2,8,32

通过在名字前以一个下划线开头来忽略未使用的变量

如果你创建了一个变量却没有使用它,Rust编译器会给你一个警告,因为它可能是个Bug。但是你有时候却需要创建这样一个变量,比如正在设计原型或者刚开始一个新项目,这时可以使用下划线作为变量名的开头,这样rust编译器就不会警告了

fn main() {
  let _x = 5;
  let y = 10;
}
warning: unused variable: `y`
 --> src/main.rs:5:7
  |
5 |   let y = 10;
  |       ^ help: if this is intentional, prefix it with an underscore: `_y`
  |
  = note: `#[warn(unused_variables)]` on by default

warning: `model` (bin "model") generated 1 warning
    Finished dev [unoptimized + debuginfo] target(s) in 0.83s
     Running `target/debug/model`

注意,只使用_和使用以下划线开头的名称有些微妙的不同:比如 _x 仍会将值绑定到变量,而 _ 则完全不会绑定

fn main() {
  let s = Some(String::from("Hello!"));

  if let Some(_s) = s {
      println!("found a string");
  }

  println!("{:?}",s);
}

我们会得到一个错误,因为s的值仍然会移动进_s,并阻止我们再次使用s。然而只使用下划线本身,并不会绑定值。上例不能编译,因为s没有被移动进 _

fn main() {
  let s = Some(String::from("Hello!"));

  if let Some(_) = s {
      println!("found a string");
  }

  println!("{:?}",s);
}
found a string
Some("Hello!")

上面的代码能很好的运行,因为没有把s 绑定到任何变量,它没有被移动

用…忽略剩余值

… 有时候比 _ 更好用

fn main() {
  struct Point {
      x:i32,
      y:i32,
      z:i32,
  }

  let origin  = Point{x:0,y:0,z:0};
  
  match origin {
      Point { x,.. } => println!("x is {}",x)
  }
}

但是使用 … 必须是无歧义。如果期望匹配的和忽略的值是不明确的,Rust会报错

let numbers = (2,4,8,16,32);

    match numbers {
        (first,_,third,_,fifth) => {
            println!("Some numbers: {},{},{}",first,third,fifth)
        },
    }
error: `..` can only be used once per tuple pattern
 --> src/main.rs:7:20
  |
7 |         (..,second,..) => {
  |          --        ^^ can only be used once per tuple pattern
  |          |
  |          previously used here

Rust不可能决定在元组中匹配second值之前应该忽略多少个值,以及在之后忽略多少个值

匹配守卫提供的额外条件

匹配守卫是一个指定于match分支模式之后的额外if条件,它也必须被满足才能选择此分支。匹配守卫用于表达式比单独的模式所能允许的更为复杂的情况

这个条件可以使用模式中创建的变量

fn main() {
    let num = Some(4);
    
    match num {
        Some(x) if x < 5 => println!("less than five: {}",x),
        Some(x ) => println!("{}",x),
        None => (),
    }
}

在模式中加入匹配守卫

     Running `target/debug/model`
less than five: 4

Some(4)第一个匹配守卫为真,让我们再来看看匹配守卫为假的情况

fn main() {
    let x = Some(10);
    let y = 10;
    
    match x {
        Some(50)  => println!("Got 50"),
        Some(n )if n == y => println!("Matched, n = {}",n),
        _ => println!("Default case , x = {:?}",x),
    }
    println!("at the end:x = {:?},y = {}",x,y)
}

也可以在匹配守卫中使用 |

fn main() {
    let x = 4;
    let y = false;
    
    match x {
        4 | 5 | 6 if y => println!("yes"),
        _=> println!("no")
    }
}

@绑定

@允许我们在创建一个存放值的变量的同时测试点其值是否匹配模式

fn main() {
    enum Message {
        Hello {id:i32},
    }

    let msg = Message::Hello {id:5};

    match msg {
        Message::Hello{id:id_variable @ 3..=7}=>{
            println!("found an id in range:{}",id_variable)
        },
        Message::Hello {id:10..=12} => {
            println!("found an id in another range")
        },
        Message::Hello {id} => {
            println!("found some other id:{}",id)
        },
    }
}
    Finished dev [unoptimized + debuginfo] target(s) in 0.72s
     Runninng `target/debug/model`
found an id in range:5

通过在3…=7之前指定id_variable@,我们捕获了任何匹配此范围的值并同时测试其值匹配这个范围的模式

第二个分支只在模式中指定了一个范围,分支相关代码没有一包含id字段实际值的变量

最后一个分支指定了一个没有范围的变量,任何值都会匹配此分支

使用@可以在一个模式中同时测试和保存变量值

总结:模式是rust中一个很有用的功能,它帮助我们区分不同类型的数据

下一章,我们会讲一些Rust的一些高级功能

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-12-03 12:54:30  更:2021-12-03 12:56:04 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 4:01:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码