8.Rust模式解构

模式解构—Pattern Destructure,其对应的就是模式构造,因此模式解构是将原本组合起来的结构分解为单独的、局部的、原始的部分。

1.模式解构示例

我们之前在学习tuple时,写过类似以下例子:

fn main() {
    let t = (1, 's', "白质".to_string());
    let (t_one, t_two, t_tree) = t;
    println!("t_one: {}, t_two: {}, t_tree: {}", t_one, t_two, t_tree);
}

运行结果:

t_one: 1, t_two: s, t_tree: 白质

以上例子就是典型的“模式解构”。

let t = (1, 's', "白质".to_string());	//将三个元素组合到一起形成一个tuple
let (t_one, t_two, t_tree) = t;	//刚好与以上相反,把一个组合数据结构,拆解成三个不同的变量

下面再举一个稍复杂些的例子:

struct A(i32, String);

struct B {
    data1 : A,
    data2 : bool
}

fn main() {
    let xb = B { data1 : A(32, "模式".to_string()), data2 : true };
    let B{
        data1 : A(val1, val2),
        data2 : val3
    } = xb;
    println!("val1: {}, val2: {}, val3: {}", val1, val2, val3);
}

运行结果:

val1: 32, val2: 模式, val3: true

模式结构不仅可以发生在let语句中,还可以发生在match、if let、while let、函数调用、闭包调用等情境中。

下面将逐一介绍。

2.match

我们从最开始的猜数字就一直在接触match,这对我们来说再熟悉不过了。

通过枚举来举一个例子:

enum data_type {
    Int(i32),
    Float(f32),
    Str(String),
    Char(char)
}

fn print_data_type(data : data_type) {
    match data {
        data_type::Int(val) => {
            println!("Int: {}", val);
        }
        data_type::Float(val) => {
            println!("Float: {}", val);
        }
        data_type::Str(val) => {
            println!("Str: {}", val);
        }
        data_type::Char(val) => {
            println!("Char: {}", val);
        }
    }
}

fn main() {
    let a = data_type::Int(1);
    let b = data_type::Float(3.3);
    let c = data_type::Str("牛逼".to_string());
    let d = data_type::Char('s');
    print_data_type(a);
    print_data_type(b);
    print_data_type(c);
    print_data_type(d);
}

运行结果:

Int: 1
Float: 3.3
Str: 牛逼
Char: s

但是如果我们把上面的Char分支删除:

match data {
    data_type::Int(val) => {
        println!("Int: {}", val);
    }
    data_type::Float(val) => {
        println!("Float: {}", val);
    }
    data_type::Str(val) => {
        println!("Str: {}", val);
    }
}

编译出错:

error[E0004]: non-exhaustive patterns: `Char(_)` not covered
 --> src\main.rs:9:11
  |
1 | / enum data_type {
2 | |     Int(i32),
3 | |     Float(f32),
4 | |     Str(String),
5 | |     Char(char)
  | |     ---- not covered
6 | | }
  | |_- `data_type` defined here
...
9 |       match data {
  |             ^^^^ pattern `Char(_)` not covered

non-exhaustive patterns:不详尽的模式、不完整的模式

Rust要求match需要对所以情况做完整的、无遗漏的匹配。exhaustive是Rust模式匹配的重要特定。

我们还可以通过下划线来表达其他情况:

fn print_data_type(data : data_type) {
    match data {
        data_type::Int(val) => {
            println!("Int: {}", val);
        }
        data_type::Float(val) => {
            println!("Float: {}", val);
        }
        _ => {
            println!("others");
        }
//        data_type::Str(val) => {
//            println!("Str: {}", val);
//        }
//        data_type::Char(val) => {
//            println!("Char: {}", val);
//        }
    }
}

运行结果:

Int: 1
Float: 3.3
others
others
因此,如果多个项目之间存在依赖关系,在上游库中对一个enum添加成员,是一个破坏兼容性的行为。增加成员后,很有可能导致下游的,atch语句编译出错。

为了解决以上问题,Rust提供了一个叫non_exhaustive的功能:

#[non_exhaustive]
pub enum A {
	//就不详细写了
}

这样下游项目中就必须使用下划线才能完整匹配。

下划线还能够用在模式匹配的其他地方,用来表示一个占位符,虽然匹配到了但是忽略它的值的情况:

fn main() {
    let t = (1, 's', "Rust编程之路");
    let (a, _, b) = t;
    println!("a: {}", a);
    println!("b: {}", b);
}

运行结果:

a: 1
b: Rust编程之路

函数参数就具备模式解构的能力:

fn func((a, _, b) : (i32, char, &str)) {
    println!("a: {}", a);
    println!("b: {}", b);
}

fn main() {
    let t = (1, 's', "Rust编程之路");
    func(t);
}

运行结果:

a: 1
b: Rust编程之路
3.if-let和while-let

我们之前在使用Option时,如果需要取出里面的值,需要做以下操作:

match data {
	Some(x) => {
		func(x);
	}
	_ => {}
}

这样做是必需的,但是比较麻烦。我们还可以采用以下方式:

if data.is_some() {
    let x = data.unwrap();
    func(x);
}

首先通过is_some判断是Some,然后通过unwrap取出数据。这样好像不是很麻烦,但是需要做两次判断是否有值。

我们可以使用if-let语法:

if let Some(x) = data {
    func(x);
}

if-let与match相比的优势在于:match需要完整匹配,而if-let则可以选择匹配感兴趣的某个特定分支,这样比较简单。

同理,while-let是同样的道理,暂不举例了。

4.函数参数模式解构

这个前面已经举过例子了。

5.ref关键字

当我们需要绑定的是被匹配对象的引用时,可以使用ref关键字。

struct A(i32, f32);

fn main() {
    let a = A(3, 3.3);
    let A(ref x, ref y) = a;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大脑白质

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值