Rust能力养成之(3):强化分支

图片

前言

上一篇,介绍了Rust语言的

  • 常规函数

  • 闭包

  • 字符串

本篇内容将涉及

  • 条件与决策

  • Match表达

  • 循环语句

条件与决策(Conditionals and decision making)

Rust中的基本条件语句,就是经典的if-else形式,似乎与其他语言并无很大不同,直接看一个代码实例。

// if_else.rs
fn main() {   let rust_is_awesome = true;   if rust_is_awesome {     println!("Indeed");   } else {     println!("Well, you should try Rust !");   }}
其实,在Rust中, if-else 结构是一个表达式(expression),而不是一个陈述语句(statement)。

这里需要说明一下,在通常的编程用意中,表达式要有返回值,而陈述语句没有。这就意味着,在Rust的if-else条件表达中,总会有一个返回值,而这个值可能是一个空的()单元类型(unit type ),也可能是一个实际值

在该表达式中大括号的最后一行负责提供返回值。需要注意一点的是,if和else各自的返回值应该具有同样的类型。而且,可见if 条件表达式也不必非要添加小括号。

上述代码结果

图片

由于返回值的存在,可以将if-else表达式赋值给一个变量,我们看来下面的代码。

// if_assign.rsfn main() {
   
       let result = if 1 == 2 {         "Wait, what ?"     } else {         "Rust makes sense"     };
    println!("You know what ? {}.", result);}


​​​​​​​上述代码结果

图片

不知道读者看到一些区别没有,如果将if-else赋值的话,语句最后要以分号结尾,这个是初始化中的所要求的的格式。如果我们去掉else{}相关的内容,如下所示​​​​​​​

fn main() {
   
       let result = if 1 == 2 {         "Wait, what ?"     };
    println!("You know what ? {}.", result);}

我们会得到编译器的报错

图片

我们分析一下原因,这是因为,在if条件为false时,表达式会返回一个空单元值(),而该表达式最后一行是一个&str类型,这意味此时有两个类型不同的潜在返回值,而这个是Rust所不能允许的,所以提示要补一个else{}语句,以保证两个分支有同样类型的返回值。

还有一点要谈,在if语句中字符串后增加的一个分号,使得编译器认为要舍弃该值,我们再来看一个实例代码。​​​​​​​

// if_else_no_value.rs
fn main() {   let result = if 1 == 2 {     "Nothing makes sense";   } else {     "Sanity reigns";   };
  println!("Result of computation: {:?}", result);}

上述代码结果

图片

可见,结果是一个空的单元值()。再看println!中,使用的是{:?}而不是{},这是因为空值无法用常规方式打印。

Match表达

Rust中的match语句真的是一个令人非常欢乐而且具有强大表现力的存在,基于C语言中的switch-case,对于多值决策,用起来格外便利,可以认为是该语言设计中的一个小亮点。

我们来看以下的代码实例​​​​​​​

// match_expression.rs
fn req_status() -> u32 {
   
       200}
fn main() {
   
       let status = req_status();    match status {
   
           200 => println!("Success"),        404 => println!("Not Found"),        other => {
   
               println!("Request failed with code: {}", other);            // get response from cache        }    }}

上述代码结果

图片

这里大致解释一下这几行代码

  • 第3-5行的函数req_status,返回的是一个简化的HTTP请求的状态码200

  • 第8行,将函数值赋给变量status

  • 第9-16,match表达式

    • 第9行,match关键词,以及对应匹配的参数status

    • 第10-14行,三个分支,称为match arms,每个arm对应可匹配的值和对应操作

    • 结构上看,=>符号左边是匹配值,右边是对应操作,同时支持单行与多行代码

    • 简单分支,逗号分隔

    • 每个分支的返回相同的类型

当需要匹配多个可能的值时,match表达式是很不错的方法,而且写起来非常简洁。与if else表达式一样,当let语句用分号分隔时,匹配表达式的返回值也可以赋给变量,所有match arm 返回相同的类型。

循环语句(Loops)

Rust中有三种循环语句,loopswhilefor,对于这三种,都可以使用continuebreak关键字来进行跳过和退出,先来看一个例子。

Loop循环​​​​​​​

// loops.rs 
fn main() {     let mut x = 1024;    loop {         if x < 0 {             break;         }         println!("{} more runs to go", x);         x -= 1;     } }

上述代码结果

图片

...

图片

loop代表一个无限循环,该代码不难理解,在其中不断削减x的值,直到小于0为止。

在Rust中,loop能够对循环体添加命名标签,经常用于多个循环存在,而只想用break退出其中一个的情形,看下代码。​​​​​​​

// loop_labels.rs
fn silly_sub(a: i32, b: i32) -> i32 {
   
       let mut result = 0;    'increment: loop {
   
           if result == a {
   
               let mut dec = b;            'decrement: loop {
   
                   if dec == 0 {
   
                       // breaks directly out of 'increment loop                    break 'increment;                } else {
   
                       result -= 1;                    dec -= 1;                }            }        } else {
   
               result += 1;        }    }    result}
fn main() {
   
       let a = 10;    let b = 4;    let result = silly_sub(a, b);    println!("{} minus {} is {}", a, b, result);}

上述代码结果

图片

在代码中,做了一个非常矫情而且低效的减法,只是为了演示在嵌套循环中使用标签。在内部的‘decrement标签中,当dec等于0时,我们可以传递一个标签给break(这里是‘increment’),并从外部的‘increment循环退出。

请读者记住这个场景,在后续的综合应用中还会有所涉及。

 

While循环

这里我们看下while循环​​​​​​​

// while.rs fn main() {   let mut x = 1000;   while x > 0 {       println!("{} more runs to go", x);       x -= 1;       }}

For循环

请读者们注意了,for循环是很值得在这里说一下的,单看语法,与之前提到loop区别不大,然而在事实上,这两者在执行过程中非常不同。

Rust中的for循环是与迭代器iterators结构体相关联的,而这一点我们会在后续讲到高级概念时候详细介绍。简言之,Rust中的for循环只适用于可转换为迭代器的类型。Range类型就是一种迭代器,可以指一个数字范围,例如 0 到10,我们可以这样使用,见下面实例:​​​​​​​

// for_loops.rs
fn main() {
   
       // does not include 10    print!("Normal ranges: ");    for i in 0..10 {
   
           print!("{},", i);    }
    println!();       // just a newline    print!("Inclusive ranges: ");    // counts till 10    for i in 0..=10 {
   
           print!("{},", i);    }}

上述代码结果如下

图片

上述代码中的第6行的0..10,左闭右开,和第13行中0..=10,左闭右闭都是Range类型相关的语法。

结语

学完这三个部分,大家是不是可以感受一点语言设计中的所体现的匠心了呢。

下一节我们开始讲一下用户自定义的数据类型,涉及结构体(Structs)枚举类型(Enums)

主要参考和建议读者进一步阅读的文献
https://doc.rust-lang.org/book

1.Rust编程之道,2019, 张汉东

2.The Complete Rust Programming Reference Guide,2019, Rahul Sharma,Vesa Kaihlavirta,Claus Matzinger

3.Hands-On Data Structures and Algorithms with Rust,2018,Claus Matzinger

4.Beginning Rust ,2018,Carlo Milanesi

5.Rust Cookbook,2017,Vigneshwer Dhinakaran

猜你喜欢

转载自blog.csdn.net/qq_40433634/article/details/112192287