首页 > 其他分享 >Rust 从入门到精通06-语句和表达式

Rust 从入门到精通06-语句和表达式

时间:2022-09-01 11:45:04浏览次数:48  
标签:语句 06 else let Rust println 表达式

1、语句和表达式

语句和表达式是 Rust 语言实现逻辑控制的基本单元。 在 Rust 程序里面,语句(Statement)是执行一些操作但不返回的指令,表达式(Expressions)计算并产生一个值。表达式可以是语句的一部分,反过来,语句也可以是表达式的一部分。

1.1 语句不返回值

fn main() {
    let x = (let y = 6);
}

这里面let y = 6 是一个语句,不能把 let 语句赋值给另一个变量,否则编译器会报错。

1.2 表达式返回值

fn main() {
    let y = {
        let x = 3;
        x + 1
    };
    println!("The value of y is: {}", y);
}

{},也是一个表达式,表达式的结果是最后一行代码,x + 1后面没有分号,表示的是表达式,如果在表达式后面加上“;”,则表示语句,语句没有返回值,则上面代码会报错。

1.3 总结

①、一个表达式总会产生一个值,因此它必然有类型。
②、语句不产生值,它的类型永远是 ();
③、如果把一个表达式加上分号,那么它就变成了一个语句;
④、如果把一个语句放到一个语句块中包起来,那么它就可以当成一个表达式使用。

Rust is primarily an expression language

翻译过来:Rust 基本上就是一个表达式语言。

Rust 除了 let / static / const / fn 等少数语句外,Rust 绝大多数代码都是表达式(expression)。所以 if / while / for / loop 都会返回一个值,函数最后一个表达式就是函数的返回值,这和函数式编程语言一致。

语句就是计算结果为()的特殊表达式。Rust 编译器,在解析代码的时候,如果碰到分号,就会继续往后执行。如果遇到语句,就执行语句;如果遇到表达式,则会对表达式求值;如果分号后面什么都没有,就补上()。

2、算术表达式

2.1、算术运算符:+ - * / %

分别是加、减、乘、除、取余。

//加、减、乘、除、取余
fn arithmetic_operation_test1(){
    let x = 100;
    let y = 10;
    println!("x={},y={},x+y={},x-y={},x*y={},x/y={},x%y={}",x,y,x+y,x-y,x*y,x/y,x%y);
}

2.2、比较运算符

注意:
①、比较运算符两边必须是同类型的,并且满足 PartialEq 约束;
②、比较表达式的类型是 bool;
③、Rust 禁止连续比较;

fn compare_test(a:bool,b:bool,c:bool) -> bool{
    a==b==c
}

编译报错:

2.3、赋值表达式

一个左值表达式、赋值运算符(=)、一个右值表达式可以构成一个赋值表达式。
①、赋值号左右两边表达式的类型必须一致,否则编译报错。
②、赋值表达式也有对应的类型和值,类型为 unit。即空的 tuple();

//赋值表达式也有对应的类型和值,类型为 unit
fn arithmetic_operation_test2(){
    let x = 1;
    let mut y = 2;

    let z = (y=x);
    //打印结果为()
    println!("{:?}",z);
}

这样能防止连续赋值,假设定义了三个 i32 类型的变量, x:i32,y:i32以及z:i32, 那么表达式 x=y=z就会发生编译错误,因为z变量是i32类型,却赋值(),编译器是不允许的。

2.4、语句块表达式

在Rust 中,语句块也可以是表达式的一部分。

语句和表达式的区分方式是后面带不带分号,如果带了分号,意味着这是一条语句,它的类型是();

如果没有带分号,它的类型就是表达式的类型。

//语句和表达式的区分方式是后面带不带分号,如果带了分号,意味着这是一条语句,它的类型是();
//如果没有带分号,它的类型就是表达式的类型。
fn arithmetic_operation_test3(){
    //语句带分号,类型是 ()
    let x:() = {println!("helloworld");};
    //Rust 将按照顺序执行语句块内的语句,并将最后的一个表达式类型返回,所以 y 最终类型是 i32
    let y = {println!("helloworld"); 5};
    println!("x={:?}",x);
    println!("y={}",y);
}

打印结果为:

2.5、if-else

①、条件表达式的类型必须是bool
②、条件表达式并未强制要求用小括号()括起来,如果括起来,编译器反而会告警,认为是多余的括号;
③、后面的结果语句块一定要用大括号括起来;

//if-else
fn if_else_test()->i32{
    if (1>2) {
        //没有加分号,返回值就是1
        1
    }else{
        2
    }
}

使用 if-else 作为表达式,一定要注意 if 和 else 分支的类型必须一致,否则就不能构成一个合法的表达式,会出现编译错误。

最常见的一种情况是 if 分支有数据返回,但是省略了 else 分支:

fn if_test() -> i32{
    if true {
        1
    }
    return 1;
}

编译报错:

这是因为 else 分支如果省略了,默认类型是 ’()‘ ,与 if 分支不匹配。

2.6、loop

在Rust中,loop表示无限死循环。

//loop
fn loop_test(){
    let mut i = 0;
    loop{
        i += 1;
        if(i == 3){
            println!("three");
            //不在继续执行后面的代码,直接跳转到loop开头继续循环
            continue;
        }
        println!("{}",i);
        if(i == 5){
            println!("that's is OK");
            //跳出循环
            break;
        }
    }
}

continue 表示本次循环内,不在执行后面的语句,直接进入下一轮循环;
break 表示跳出循环,不在执行。

注意:在Rust中,我们可以在 loop、while、for循环前面加上“生命周期标识”,在内部循环中,可以通过break、continue选择跳转到哪个循环标识。

2.7、while

带条件判断的循环语句。

//while循环
fn while_test(){
    let mut n = 1;
    while(n < 100){
        if(n%2==0){
            println!("偶数:{}",n)
        }else{
            println!("奇数:{}",n)
        }
        n+=1;
    }
}

2.8、loop{} 和 while(true){}

从语法上理解,loop{} 和 while(true){} 这两种是没有任何区别的。
但相比于其他很多语言,Rust 语言要做更多的静态分析,loop 和 while true 语句在运行时没有任何区别,他们主要会影响编译器内部的静态分析结果。
比如:

let x;
loop{
    x = 1;
    break;
}
println!("{}",x);

上面语句在Rust中完全合理,因为编译器可以通过流程分析推理出x=1,必然在println!之前执行过,所以打印x的值是完全合理的。
再比如对于while true 语句:

let x;
while(true){
    x = 1;
    break;
}
println!("{}",x);

报错如下:

因为编译器会觉得while 语句的执行和条件表达式在运行阶段的值有关(有可能while false,导致没有运行 while 里面的语句,从而 x 没有初始化),于是编译器直接抛出一个未初始化异常。

2.9、for

Rust 中的for循环类似其他语言中的 for-each 循环。
for循环的主要用处是利用迭代器对包含同样类型的多个元素的容器进行遍历,如数组、链表、HashMap、HashSet等。

fn for_test(){
    let array = &[1,2,3,4,5];
    for i in array {
        println!("The Numer is {}",i);
    }
}

3、常见错误

3.1 连续赋值报错

fn f(a:bool,b:bool,c:bool) -> bool{
    a == b == c
}

报错如下:

3.2 漏掉 else 分支报错

如果 else 分支省略掉了,编译器会认为 else 分支的类型默认为(),但是 if 分支返回的是 i32 数据类型。

我们知道,使用 if-else 作为表达式,一定要注意 if 和 else 分支的类型必须一致,否则就不能构成一个合法的表达式,会出现编译错误。

fn if_test() -> i32{
    if true {
        0
    }
    return 1;
}

编译报错:

标签:语句,06,else,let,Rust,println,表达式
From: https://www.cnblogs.com/ysocean/p/16646003.html

相关文章

  • DBA常用查询语句
    ----查看表空间的使用情况SELECTA.TABLESPACE_NAME,A.BYTESTOTAL,B.BYTESUSED,C.BYTESFREE,(B.BY......
  • 循环语句:while
    循环语句:while1.while语句结构:while+条件示例1:whileTrue:print("人生苦短,我用Python。")运行得到的结果是循环打印“人生苦短,我用python。”示例2:while......
  • Codeforces Round #606(B-D)
     Dashboard-CodeforcesRound#606(Div.2,basedonTechnocup2020EliminationRound4)-CodeforcesB.MakeThemOdd题意:一个数组,每次选择一个数,将数组中的......
  • 新手教新手:3 SQL Select 语句 GROUP BY 子句
    新手教新手:3SQLSelect语句GROUPBY子句SQLSELECT语句中的下一个子句是GROUPBY子句。这将为列中的每个唯一值创建一组行。在按分组的列中具有相同值的所有行将彼......
  • 使用selenium自动化模块实现登录12306
    importtimefromselenium.webdriverimportChromefromselenium.webdriver.chrome.optionsimportOptionsfromselenium.webdriver.common.byimportByfromselenium.w......
  • 【lwip】06-网络接口层分析
    目录前言6.1概念引入6.2网络接口层数据概念流图6.3网卡收包程序流图6.4网卡数据结构6.4.1structnetif源码6.4.2字段分析6.4.2.1网卡链表6.4.2.2网络IP6.4.2.3......
  • C20220806T1 暴力计算
    给定一张图,按照边权走,求总边权达到\(M\)时用的最短长度。\(n\leq100,M\leq10^{18}\)。首先可以用\(dp[i][j][k]\)表示从\(i\)出发通过\(2^k\)步走到\(j\)......
  • C20220806T3 如何愉快地与方格玩耍
    给定\(n\timesn\)的黑白方格,期初所有颜色均为白色,支持以下操作翻转\([l,r]\)行/列的颜色翻转质数/合数行/列的颜色求\([l1,r1]\)行、\([l2,r2]\)列围成的区......
  • C20220806T2 枚举计算
    有\(n\)个点,求从1号点到\(n\)号点的最短路径,但有某些点有前驱,必须先到了前驱才能到达这个点,允许有多个点同时出发。\(n\leq3000,m\leq30000\)。一看,这不是最短路......
  • mysql安装及10061错误解决
    mysql出现10061错误解决方法 1.开始菜单->运行(cmd)->寻径到MySQL文件中的bin目录下如:D:\MySQL\mysql-5.6.24-win32\bin2.输入指令:mysqld--skip-grant-tables 回车//......