Rust学习笔记2-Rust基础语法

概述

这篇文章介绍了 Rust 语言的基础语法规则,学会了这些语法内容,就可以使用 Rust 编写简单的程序了,文章内容包括 Rust 中最基础的程序结构、注释、基础数据类型、变量定义、函数定义、分支与循环结构。

一个简单的 Rust 程序代码

1
2
3
4
5
6
7
fn main() { 
// 定义变量
let mut name = "C/C++";
println!("Hello, {}!", name); // 打印输出
name = "Rust"; // 修改变量值
println!("Hello, {}!", name);
}

Rust 基础代码结构

Rust 是一种大小写敏感的编程语言。

Rust 代码语句使用分号 ; 结尾,代码块使用大括号 {} 包括。

在 Rust 中,使用 fn 关键字定义函数,使用 let 关键字定义变量。

Rust 中程序入口为 main 函数。

Rust 注释

单行注释

和大部分编程语言一样,Rust 使用双斜杠 // 添加单行注释,单行注释可以添加在独立行或行尾。

1
2
// 定义变量
let mut name = "C/C++"; // 定义变量

// 会将标记处至后面第一个换行符的内容标识为注释。

多行注释

Rust 使用 /**/ 添加多行注释。

1
2
3
4
5
6
/* 
注释1
注释2
*/

/*注释1*/ print!("abc"); /* 注释2 */

注:上述程序将输出 abc

文档注释

Rust 中使用三斜杠 /// 添加文档注释,使用文档注释函数后将在 ide 中快捷看到函数的注释信息。

文档注释的内容可以使用 cargo doc 命令生成对应的 html 文档。

文档注释中可以使用 markdown 语法添加文档格式。

1
2
3
4
5
6
7
8
9
fn main() { 
print_hello();
}

/// # print_hello
/// > This function can print `hello`
fn print_hello()->(){
print!("hello");
}

Rust 定义变量

不可变变量与可变变量

Rust 中使用 let 关键字定义变量,以此定义的变量是不可变的,即不能重新赋值。

如果要定义可变的变量,需要使用 let mut 关键字定义。

1
2
3
4
5
6
7
8
fn main() { 
let a = 1; // 定义一个不可变变量 a
let mut b = 2; // 定义一个可变变量 b
// a = 2; // 将报错 cannot mutate immutable variable `a`
b = 3;
let 中文 = "你好"; // 变量名可以是中文,但不推荐使用中文命名
println!("{}", 中文);
}

以上代码在编译时将报错,提示 cannot mutate immutable variable `a` ,意思是不能修改不可变变量 a。

为什么 Rust 中的变量不可变?

在大量的编程实践中,人们发现一个规律,开发者常常会用变量存储一个不可改变的值,仅仅是为了将这个值存储起来,后面好用。这些用途上不可变的变量,往往极大地影响并发程序中对变量的使用,因此 Rust 默认状态下保护了所有的变量。

指定变量类型

Rust 是静态编译语言,在编译时必须知道所有变量的类型。

在 Rust 中,为变量赋值后,编译器会根据赋的值自动推断出变量的类型,如果不赋值则必须指明数据类型,否则编译将报错。

如果可能的类型比较多(如把 String 转成整数的 parse 方法),也必须添加类型标识,否则编译会报错,例如 let x: u32 = "200".parse().expect("Not a number")

当我们需要指定数据类型时,可以在变量名后添加 : 和类型标识,来指定该变量的数据类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let x = 1; // 自动推断类型为 i32
let y = 3.14; // 自动推断类型为 f64
let z = 1_u8; // 自动推断类型为 u8
let s = "hello"; // 自动推断类型为 &str
let bb = false; // 自动推断类型为 bool
let cc; // 自动推断类型为 i32
cc = 1;
// let dd; // 编译报错 type annotations needed

let a: i8 = 1; // 指定类型为 i8·
let mut b: u8 = 255; // 指定类型为 u8
let c: f32 = 3.14; // 指定类型为 f32
let mut s2: &str = "hello"; // 指定类型为 &str
let bb2: bool = true; // 指定类型为 bool

注:在给变量赋值时,右侧的具体值称为字面量,字面量值后面可以通过下划线 _ 加类型方式指定字面量的数据类型,如 _u8 指定值为 u8 类型。

Rust 默认将整形数字推断为 i32 类型,将浮点型数字推断为 f64 类型。

变量的隐藏(shadowing)

在 Rust 中,可以使用相同名字声明新的变量,新的变量就会 shadow(隐藏,或称为遮蔽、重影)之前声明的同名变量。

1
2
3
4
5
let a = 100; // 首次声明变量 a
// a = -100; // 报错,无法效果不可变变量的值
let a = -100; // 隐藏之前的变量 a,新的变量 a 值为 -100
let a = a + 100; // 隐藏之前的变量 a,新的变量 a 值为 之前 a 的值+100,值为 0
let a = "hello"; // 隐藏之前的变量 a,新的变量 a 数据类型为 `&str` ,值为 hello

隐藏是 Rust 中比较重要和特别的概念,在其他编程语言没有这种语法规则。

常量(constant)

Rust 中使用 const 定义常量,常量在声明时必须指定数据类型,常量赋值后不可变。

常量名使用全大写字母,多个字母间使用下划线 _ 分隔。

常量在其声明的作用域内一直有效。

1
2
const PI: f64 = 3.14;
const MAX_CNT: i32 = 100;

常量与不可变变量的区别:

  • 常量不可使用 mut,常量永远都是不可变的。
  • 声明常量使用 const 关键字,必须指定数据类型。
  • 常量可以在任何作用域中声明,包括全局作用域,使用 let 声明的变量只能在函数中使用。
  • 常量只能绑定到常量表达式,无法绑定到函数的调用结果或只能在运行时才能计算出的值。

静态变量(static)

静态变量可在函数外声明,被所有函数共享。

使用 static 关键字声明静态变量,声明时必须指定类型和初始值,如 static MAX_CNT:i32 = 100;

默认静态变量是不可改变的,如果需要修改要使用 static mut 声明,如 static mut CURR_CNT:i32 = 0;

Rust 认为修改静态变量值是 “不安全” 行为,要放在 unsafe 块或函数中。因为在多线程程序中,同时有多个线程修改静态变量值,会出现不可预测的情况。

1
2
3
4
5
6
7
8
9
static MAX_CNT:i32 = 100;
static mut CURR_CNT:i32 = 0;

fn main() {
// MAX_CNT = 1; // 会报错,MAX_CNT 是无法修改的
unsafe {
CURR_CNT = 1; // CURR_CNT 是可修改的,但 Rust 认为这种操作是不安全的,要放在 unsafe 块或函数中
}
}

Rust 数据类型

字面量

字面量是指在程序中无需变量保存,用于表示固定的值,可直接表示为一个具体的数字或字符串的值,即数据在程序中的书写格式。字面量只能作为右值出现,所谓右值是指等号右边的值。

在 Rust 中,主要有四种字面量类型:整数类型、浮点类型、布尔类型、字符类型。

整数的字面值

整形字面量中间可以加 _ 增强数据可读性,十六进制以 0x 打头,八进制以 0o 打头,二进制以 0b 打头,字节类型以 b'' 表示。

除了 byte 类型,其他数值字面值都允许使用类型后缀,如 25u8

进制 示例 备注
十进制 10_086,255u8、100_000_086_i64
十六进制 0xff,0xFFFF_FFFFu32
八进制 0o177、0o77_i8、0o777_777_u32
二进制 0b1111_0000
字节(u8类型) b’A’ 仅限于 u8 类型
1
2
3
4
5
6
7
8
9
10
let a = 10_086;
let b = 255u8;
let c = 100_000_086_i64;
let d = 0xff;
let e = 0xFFFF_FFFFu32;
let g = 0o77_i8;
let h = 0o777_777_u32;
let i = 0b1111_0000;
let j = 0b11_111_111u8;
let k = b'A';
浮点型字面量

浮点型也可以使用下划线 _ 增强数据可读性,也可以添加类型后缀。如

1
2
3
4
5
let a = 1.0;
let b: f32 = 2.0;
let c = 3.0_f32;
let d = 10_086.123;
let e = 100_86.123f32;
布尔型字面量

Rust 中布尔类型字面量包括 truefalse

字符型字面量

字符型字面量以单引号 '' 包括, 如 A'你''\t'

基础数据类型

整形(Integer)

整形即整数,Rust 中整形分为有符号整形(integer)和无符号整形(unsigned integer),有符号整形标识符以 i 打头,无符号整形标识以 u 打头,后面的数字表示数据占的位数(bit)。

Rust 中默认的整形类型是 i32

长度 有符号整形 无符号整形
8bit i8 u8
16bit i16 u16
32bit i32 u32
64bit i64 u64
128bit i128 u128
arch isize usize

注:arch 长度由运行程序的计算机系统架构确定,如在 32 位架构中长度为 32bit,在 64 位架构中长度为 64bit。

isizeusize 的主要使用场景是对某种集合进行索引操作。

整数的溢出:当为整形变量赋值时,如果超出了该类型的边界,根据程序编译模式会发生以下两种情况:

  • 调试模式下编译:Rust会检查整数溢出,如果发生溢出,程序在运行时就会 panic(恐慌,大致可理解成异常)。
  • 发布模式下(--release)编译:Rust 不会检查可能导致 panic 的整数溢出,如果发生溢出, Rust 会执行 “环绕” 操作,如为 u8 变量赋值 256 会变成 0,赋值 257 会变成 1。
浮点型(Floating-Point)

浮点型即小数,Rust 中浮点型有双精度浮点型 f64 和单精度浮点型 f32 ,长度分别为 64bit 和 32bit。

Rust 的浮点型使用 IEEE-754 标准来表述。

Rust 中默认的浮点型类型是 f64 ,在现代计算机处理器中对两种 浮点数的计算速度几乎相同,但 64 位浮点数精度更高。

布尔型(Boolean)

布尔值表示是或否两种状态,Rust 中布尔型为 bool ,占 1 个字节,值为 truefalse

注意,Rust 中布尔值不能是数字,不能像某些编程语言中 0 表示 false,1 表示 true。

字符型(Char)

字符型表示单个字符,在 Rust 中字符型以 char 表示,单个字符是一个 Unicode 字符,长度为 4 个字节,这与其他编程语言有区别。

字符值以单引号包括,如果是特殊字符需要使用转义符 \ 进行转义,如单引号 '\''

字符值可以是中文、藏文、日文、韩文、特殊字符、emoji 表情等合法 Unicode 字符。

1
2
3
4
5
6
7
let a = '你';
let b = 'b';
let c: char = 'C';
let d: char = '\t';
let e: char = '\'';
let f: char = 'ཀ'; // 一个藏文符号
let g: char = '😂';

字符串(String、&str)

Rust 中字符串有两种类型 String&str ,一般情况下 &str 更加实用,因为它几乎具备 String 的所有常用功能。如果不需要把字符串当做一个可以编辑的数据对象时,建议优先选择使用 &str 数据类型。

Rust 中的字符串常量用双引号 "" 包含,这种数据的类型是字符串切片 &str ,如 "Hello world"

字符串类型(String)可以使用 from 方法从字符串常量获得,如 let string = String::from("This is String")

Rust 中字符串可以灵活地追加字符或其他字符串,使用 push() 方法追加字符,使用 push_str() 方法追加字符串。

字符串变量使用 len() 方法获取字符串长度,使用 eq() 方法比较两个字符串。

1
2
3
4
5
6
7
8
9
10
fn main() { 
let a: &str = "Hello world"; // 字符串常量,数据类型为 &str
let mut string = String::from("This is String"); // 使用 String 的 from 创建字符串数据类型
string.push('!'); // 追加字符
string.push_str(" This is new string."); // 追加字符串
println!("{}", string);
let b = "Say 你好"; // 长度为10,3个英文字母,1个空格,每个汉字(UTF-8编码)占 3 个字节
println!("b len={}",b.len()); // 使用 len() 方法获取字符串长度
println!("{}", b.eq("Say 你好")); // 使用 eq() 方法判断字符串是否相同
}

元组(Tuple)

元组是一系列数据的组合,可以包含不同类型数据。元组的长度是固定的,一旦声明就无法改变。

Rust 中元组的值用小括号 () 包括,值之间以逗号 , 分隔;元组的类型定义以小括号 () 包括,元素类型以逗号 , 分隔。

取元组类型的值时,可以使用变量名加 . 索引方式取值,如 a.0 取第一个元素值。

可以使用模式匹配来解构(destructure)元组来获取元素的值。

元组的使用场景是存放按顺序存储的若干数据,而不用像结构体一样为每个数据起一个名字。另外当函数需要返回多个数据时,使用元组也很方便。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
fn main() { 
let a = (1, "hello", 3.14); // 自动推断为元组类型:(i32, &str, f64)
println!("{},{},{}", a.0, a.1, a.2);

let b: (i32, &str, f64) = (2, "world", 1.732);
println!("{},{},{}", b.0, b.1, b.2);

let (x,y,z) = b; // 模式匹配结构元组
println!("{},{},{}", x, y, z);

let mut c: (i32, &str, i32) = (1, "XiaoMing", 18); // 创建可变元组
c.2 = 20; // 修改元组成员值
println!("{}",c.2);

let d = get_point();
println!("point:({},{})", d.0, d.1);
}

// 需要返回多个数据的函数,可使用元组作为返回值类型
fn get_point() -> (i32,i32) {
(0,0)
}

数组(Array)

数组是一组相同类型数据的组合结构,数组在声明后成员数量就固定不变了。

Rust 中数组值以中括号 [] 包括,各元素值之间使用逗号 , 分隔;数组定义使用中括号包含类型和长度 [类型; 数组容量] 表示,如定义一个 3个成员的 i32 类型数组,类型为 [i32; 3]。定义数组时,数组长度可以使用常量指定,作为数组长度的常量数据类型是 usize,不能使用 let 声明的变量。

如果数组成员值相同,可以使用 [值; 数组长度] 方式创建数组,如 let c = [3; 5] 相当于 let c = [3, 3, 3, 3, 3]

使用 [索引值] 获取数组中的值,如 a[1] 为数组中第二个值。如果访问的索引超出数组范围,编译会通过,运行时会报错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
fn main() { 
let a = [1,2,3]; // 自动推断数据类型为 [i32; 3]
println!("{},{},{}",a[0],a[1],a[2]); //使用索引下标访问数组值

let b: [&str; 3] = ["red", "green", "blue"];

let c = [3; 5]; // 填充数组,相当于 [3, 3, 3, 3, 3]

let mut d: [i32; 3] = [0; 3]; // 创建可变数组
d[0] = 1; // 修改数组值
d[1] = 2;
d[3] = 3;

const ARRAY_LEN: usize = 5;
let f: [i32; ARRAY_LEN]; // 使用常量指定声明数组的长度
}

注:数组的数据存放在 stack(栈)上,而不是 heap(堆)上。

Range

Rust 中的 Range 类型用于创建指定范围内的数字集合,创建时指定开始和结束数字,即可创建从开始值到结束值(不包含结束值)的范围数据, 语法为 let a: Range<i32> = 1..4;

Range 提供了 rev() 方法,用来反转 Range ,方法返回一个迭代器,可用 for 循环遍历。

1
2
3
4
5
6
7
8
9
10
11
use std::ops::Range;

fn main() {
let a: Range<i32> = 0..3; // 定义一个 Range
for i in a {
println!("{}", i);
}
for i in (0..3).rev() { // 使用 rev() 方法反转一个 Range
println!("{}", i);
}
}

运算

基础数学运算

Rust 中基础数学运算包括加(+)、减(-)、乘(*)、除(/)、取模(%)。

Rust 数学运算支持在运算符后加等号 = 实现自运算,如 x += 1

Rust 中基础数学运算必须保证所有参与运算的值是相同类型,如果数据类型不同,将无法计算。不同类型的整形不能做计算,如 1 + 1_i8;整形和浮点型不能之间计算,如 1 + 1.1 。不同类型的数据需要进行类型转换后再参与运算,可以使用 as 关键字进行类型转换,如 1_i8 as f64

Rust 中不支持 ++-- 运算,因为这两个运算符会影响代码可读性,开发者难以意识到值可能发生了改变。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
fn main() {
let a: i8 = 1 + 1 + 1;
let b = 3 - 2;
let c = 2 * 3;
let d = 10 / 6;
let e = 10 % 3;
let f = 1.0 + 1.1;
let g = 10.0 / 3.0;
println!("a={}",a);
println!("b={}",b);
println!("c={}",c);
println!("d={}",d);
println!("e={}",e);
println!("f={}",f);
println!("g={}",g);
// 不同类型数据的运算
let h: i32 = 3;
let i: f64 = 10_f64;
let j = i / (h as f64); // 将整形转成浮点型后再参与计算
let k = 1_i32 + (1_i8 as i32); // 将不同整形转成相同整形后再参与计算
println!("j={}",j);
println!("k={}",k);
}

数学运算函数

Rust 中整形和浮点型数据自含一些数学运算函数,如整形的平方、取绝对值,浮点型的三角函数计算、开方、对数计算等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fn main() {
let a: i8 = 0 - 1 - 1;
let b = a.pow(3); // 整数的平方,-2 的三次方等于 -8
println!("b={}",b);
let c = a.abs(); // 取绝对值,-2 的绝对值为 2
println!("c={}", c);
let d: f32 = (30 as f32) * 3.141592654/180.0; // 将角度 30度转为弧度
let e = d.sin(); // 求三角函数 sin30,值为 0.5
let f = d.cos(); // 求三角函数 cos30,值约等于 0.8660254
println!("sin30={}", e);
println!("cos30={}", f);
let g = (3.0_f32).sqrt(); // 求根号3
let h = g / 2.0; // 二分之根号3,即 cos30 的值
println!("h={}",h);
}

注意:三角函数运算时使用的是弧度。

逻辑运算

逻辑运算的结果是布尔型,逻辑运算包括逻辑判断和布尔值之间的逻辑运算。

逻辑运算名 逻辑运算符 示例 示例结果
大于 > 3>2 true
小于 < 3<2 false
等于 == 3==2 false
大于或等于 >= 3>=2 true
小于或等于 <= 3<=2 false
不等于 != 3!=2 true
与运算 && true && false false
或运算 ` `
非运算 ! !true false
异或运算 ^ true^false true

位运算

位运算是指按二进制位,即bit位进行运算,常用位运算包括:与(&)、或(|)、取反(!)、异或(^)、左移(<<)、右移(>>)。

1
2
3
4
5
6
7
8
9
10
11
12
13
fn main() {
let a: u8 = 0b1101_1000;
let b: u8 = 0b1010_0101;
println!("a =0b{:08b}", a);
println!("b =0b{:08b}", b);
println!("a&b =0b{:08b}", a&b);
println!("a|b =0b{:08b}", a|b);
println!("!a =0b{:08b}", !a);
println!("!b =0b{:08b}", !b);
println!("a^b =0b{:08b}", a^b);
println!("a<<1=0b{:08b}", a<<1);
println!("a>>1=0b{:08b}", a>>1);
}

使用 println!() 宏打印输出时,可以指定输出参数的编码格式,方便查看结果。

如以上代码示例中的 {:08b} 表示将参数值以二进制格式输出(:b),输出内容长度为 8 位,不足 8 位的前面补 0。

Rust 函数定义

在 Rust 中使用 fn 关键字定义函数,函数定义格式为:fn 函数名(参数1:参数1类型, 参数2:参数2类型,...)->返回值类型 {函数体},定义函数时可以不加参数,即定义无参函数,也可以不指定返回值类型。函数调用方式为 函数名(参数1, 参数2,...)

Rust 中的变量名和函数名使用 snake case 命名规范,即全使用小写字母,单词间使用下划线分隔,如 say_hello。

Rust 函数不区分定义的先后顺序,不像 C 语言要先定义才能使用。

Rust 中函数体可包含一些列语句,可选由一个表达式结束,Rust 中大多数函数会以最后一个表达式的值作为函数的返回值,如果想提前返回可以使用 return 关键字。

语句是执行一些动作的指令,如函数定义或以分号结尾的一句代码。在 Rust 中不允许将语句赋值给一个变量,如 let a = (let b = 1) 是不合法的。

表达式可执行一些运算,如算式 3+2,最终得到一个值,所有字面值都是表达式,如 5"hello"

Rust 中有函数对象(Function object)的概念,类似 C/C++ 中的函数指针,可以将函数当做变量或参数进行传递和使用,它使得动态标记函数变为可能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
fn main() { 
say_hello(); // hello
hello_someone("rust"); // hello, rust
let a = get_five();
println!("a = {}", a); // a = 5
let b = plus_five(a);
println!("b = {}", b); // b = 10
let c = get_max(3, 5);
println!("c = {}", c); // c = 5
// 函数对象
let mut func: fn();
func = say_hello; // 给函数对象赋值,右值为函数名
func(); // 函数对象调用
func = say_hi; // 修改函数对象的值
func();
//带参数的函数对象
let mut func2: fn(&str);
func2 = hello_someone;
func2("world!");
// 有参带返回值的函数对象
let func3: fn(i32,i32) -> i32;
func3 = get_max;
let max_val = func3(2,3);
}

// 无参参数
fn say_hello() {
println!("hello");
}

fn say_hi() {
println!("Hi");
}

// 有参函数
fn hello_someone(name: &str) {
println!("hello, {}", name);
}

// 无参有返回值函数
fn get_five() -> i32 {
5
}

// 有参有返回值函数
fn plus_five(x: i32) -> i32 {
x + 5
}

fn get_max(x: i32, y: i32) -> i32 {
if x > y {
return x; // 使用 return 关键字返回结果
}
y // 最后一个表达式作为函数返回值
}

闭包(Closure)

闭包、Lambda表达式、匿名函数,描述的是同一个概念,是一种快捷传递函数的方式,广泛用于异步编程。

Rust 中闭包的定义方式是 |参数1,参数2,...|->返回值类型{函数体} ,其中返回值类型支持自动推断,可以省略。

1
2
3
4
5
6
fn main() {
let fun = |x: i32, y: i32| -> i32 {
x + y
};
let a = fun(3, 2);
}

Rust 分支结构

if-else 分支

if-else 用于分支判断,Rust 中 if-else 条件语句的格式如下:

1
2
3
4
5
if 判断条件 {
// 一些代码
} else {
// 另一些代码
}

Rust 中的判断条件表达式不需要使用小括号包含,代码语句必须使用大括号包含。

Rust 中条件表达式必须是布尔类型(bool),不能是数字。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
fn main() {
let a = 5;
// if-else
if a > 0 {
println!("a>0");
} else {
println!("a<=0");
}
// if
if a<10 {
println!("a<10");
}
//if-else-if
let b = 83;
if b>100 || b<0 {
println!("成绩错误");
} else if b>85 {
println!("优");
} else if b>75 && b<=85 {
println!("良");
} else if b>=60 && b<= 75 {
println!("中");
} else {
println!("不及格");
}
}

三元表达式

在 Rust 中不支持三元表达式,但 Rust 中可以使用 if-else 来实现相同效果。

1
2
3
4
5
6
7
8
9
10
11
let a = 65;
let b = if a>0 {1} else {-1};
let c = if a>85 {
"优"
} else if a>75 {
"良"
} else if a>=60 {
"中"
} else {
"不及格"
};

match 语句

Rust 中没有 switch 语句,Rust 中的多分支判断使用 matchmatch 每个分支结束时不用 break 跳出。

Rust 中的 match 判断项也不需要使用小括号包含,多个匹配项使用 | 分隔,每个匹配项后使用 =>{} 指定执行代码,多个匹配项之间使用逗号 , 分隔。

Rust 中 match 必须匹配所有可选项,在最后可以使用下划线 _ 匹配所有剩余项,类似其他编程语言中的 default

Rust 中 match 也可以返回值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
fn main() {
let a = 1;
match a {
1 => { // 匹配单项
println!("a=1");
},
2|3|4 => { // 匹配多项
println!("a=2 or 3 or 4");
},
_ => { // 剩余项
println!("other number");
}
}
let b = match a { // match返回值
1 => {
"一"
},
2|3|4 => {
"二、三、四"
},
_ => {
"其他"
}
};
println!("{}",b);
}

Rust 循环结构

loop 循环

Rust 中使用 loop 创建无限循环。

Rust 中的 loop 循环可以作为表达式,在 break 关键字后指定循环的返回值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
fn main() {
let mut a = 0;
loop {
if a == 100 {
break;
}
if a%2 == 1 {
a += 1;
continue;
}
println!("{}", a);
a += 1;
}
let b = ['h', 'e', 'l', 'l', 'o'];
let mut i = 0;
let location = loop { // 获取loop循环的返回值
if b[i] == 'l' {
break i;
}
i += 1;
};
println!("location: {}", location);
}

while 循环

Rust 中 while 循环与其他编程语言的 while 循环用法类似,先判断条件是否满足,条件为真则进入循环体,直到条件不满足退出循环,在循环体中可使用 continue 跳过本次循环,使用 break 跳出整个循环。

Rust 中条件表达式不使用小括号包含。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
fn main() {
let mut a = 0;
while a<10 {
if a == 3 { // 当值为 3 时,跳过本次循环
println!("{} skip", a);
a += 1; // 由于continue会跳过本次循环体后续内容,必须在这里进行加一,否则会出现死循环
continue;
}
if a == 6 { // 当值为 6 时,中断循环
println!("{} break", a);
break
}
println!("{}",a);
a += 1;
}
}

for 循环

Rust 中的 for 循环是 foreach 循环,是专门用来遍历可迭代对象的语法,用法是 for 变量名 in 迭代器 {函数体}

迭代器是一类对象,如数组、Vector等,其实现了迭代器相关的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
fn main() {
let arr = [2, 1, 3, 5, 6, 4];
for i in arr { // 遍历数组
println!("{}", i);
}

for i in 1..5 { // 使用 Range 类型快速的递增迭代 1~5,不包含 5
println!("{}", i);
}

for i in 0..arr.len() { // 按数组下标遍历数组
println!("arr[{}]={}", i, arr[i]);
}

let mut v: Vec<i32> = Vec::new();
v.push(3);
v.push(5);
v.push(8);
for i in v { // 遍历Vector
println!("{}", i);
}
}

参考资料

  • 樊少冰, 孟祥莲. 《Rust编程从入门到实战》. 2022