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;
}

编译报错:

Rust 从入门到精通06-语句和表达式的更多相关文章

  1. Rust 从入门到精通03-helloworld

    安装完成 Rust 之后,我们可以编写 Rust 的 Hello Word.这里介绍两种方式,一种是rust原生方式,一种是利用 cargo 工具(重要) 1.rustc 方式 1.1 创建项目目录 ...

  2. Rust 从入门到精通01-简介

    1.rust 从哪里来 Rust语言在2006年作为 Mozilla 员工 Graydon Hoare 的私人项目出现,而 Mozilla 于 2009 年开始赞助这个项目.第一个有版本号的 Rust ...

  3. Rust 从入门到精通05-数据类型

    Rust 是 静态类型(statically typed)语言,也就是说在编译时就必须知道所有变量的类型. 在 Rust 中,每一个值都属于某一个 数据类型(data type),分为两大类: ①.标 ...

  4. iOS回顾笔记(06) -- AutoLayout从入门到精通

    iOS回顾笔记(06) -- AutoLayout从入门到精通 随着iOS设备屏幕尺寸的增多,当下无论是纯代码开发还是Xib/StoryBoard开发,自动布局已经是必备的开发技能了. 我使用自动布局 ...

  5. JavaScript从入门到精通(转)

    JavaScript从入门到精通 转自: https://github.com/Eished/JavaScript_notes 视频连接:https://www.bilibili.com/video/ ...

  6. 1、ASP.NET MVC入门到精通——新语法

    本系列目录:ASP.NET MVC4入门到精通系列目录汇总 在学习ASP.NET MVC之前,有必要先了解一下C#3.0所带来的新的语法特性,这一点尤为重要,因为在MVC项目中我们利用C#3.0的新特 ...

  7. 5、ASP.NET MVC入门到精通——NHibernate代码映射

    本系列目录:ASP.NET MVC4入门到精通系列目录汇总 上一篇NHibernate学习笔记—使用 NHibernate构建一个ASP.NET MVC应用程序 使用的是xml进行orm映射,那么这一 ...

  8. 10、ASP.NET MVC入门到精通——Model(模型)和验证

    本系列目录:ASP.NET MVC4入门到精通系列目录汇总 模型就是处理业务,想要保存.创建.更新.删除的对象. 注解(通过特性实现) DisplayName Required StringLengt ...

  9. 23、ASP.NET MVC入门到精通——业务层和数据层父类及接口-T4模板

    本系列目录:ASP.NET MVC4入门到精通系列目录汇总 在上一篇中,我们已经把项目的基本框架搭起来了,这一篇我们就来实现业务层和数据层的父接口及父类. 1.我们先来定义一个业务层父接口IBaseB ...

随机推荐

  1. [二进制漏洞]栈(Stack)溢出漏洞 Linux篇

    目录 [二进制漏洞]栈(Stack)溢出漏洞 Linux篇 前言 堆栈 堆栈(Stack)概念 堆栈数据存储方式 函数调用 函数调用C语言代码 函数调用过程GDB调试 函数Call返回原理 函数栈帧 ...

  2. 你真的了解git的分支管理跟其他概念吗?

    现在前端要学的只是太多了,你是不是有时会有这个想法,如果我有两个大脑.一个学Vue,一个学React,然后到最后把两个大脑学的知识再合并在一起,这样就能省时间了. 哈哈,这个好像不能实现.现实点吧!年 ...

  3. ansible变量引用

    1. 在/etc/ansible/hosts默认文件中定义变量 [test] 192.168.163.130 #[test:vars] #key=ansible 或者 192.168.163.130 ...

  4. Markdown扩展语法

    目录 Markdown 语法补充 一.快速生成 HTML 表格代码 在线表格编辑器--TablesGenerator 二. 插入视频.音频或GIF 1. 视频 2. 音频 方法一 方法二 方法三 3. ...

  5. Java + Selenium + OpenCV解决自动化测试中的滑块验证

    最近工作过程中,一个常用的被测网站突然增加了滑块验证环节,导致整个自动化项目失效了. 为了解决这个滑块验证问题,在网上查阅了一些资料后,总结并实现了解决方案,现记录如下. 1.滑块验证思路 被测对象的 ...

  6. CSS(十四):盒子模型

    页面布局的本质 网页布局过程: 先准备好相关的网页元素,网页元素基本都是盒子. 利用CSS设置好盒子样式,然后放到相应的位置 往盒子里面装内容 网页布局的本质:就是利用CSS摆盒子 盒子模型 组成 所 ...

  7. Java-类与对象-多态

    Java类与对象-多态 多态:类与对象三大特征之一 什么是多态? 同类型的对象,执行同一个行为,会表现出不同的行为特征. 多态的形式 1.父类类型 对象名称 = new 子类构造器(); 2.接口 对 ...

  8. CF1612D X-Magic Pair

    题意: 给一个数对 \((a,b)\) ,每次可以进行操作 \((a,b) \to (|a-b|,b)\) 或 \((a,b) \to (a,∣a−b∣)\),问最后能否令 \(a=x\) 或 \(b ...

  9. 基于cornerstone.js的dicom医学影像查看浏览功能

    最近由于项目需求,需要医学影像.dcm文件的预览功能,功能完成后,基于原生Demo做一个开源分享. 心急的小伙伴可以先看如下基于原生js的全部代码: 一.全部代码 <!DOCTYPE html& ...

  10. 注解_概念和注解_JDK内置注解

    注解: 概念:说明程序的,给计算机看的 注解:用文字描述程序的,给程序员看的 定义:注解(Annotation),也叫元数据.一种代码级别的说明.他是JDK1.5及以后的版本引入的一个特性,与类,接口 ...