编程语言中最基本的就是基本数据类型(premitive type),程序员所有的自定义类型最终都将落实到基础数据类型的排列和操作上。程序的运行需要进行逻辑的控制,在图灵完备的语言中,都具有完善的程序流控制语法。
在Rust中,基本类型、语句/表达式,程序流程控制都被安排得明明白白,这篇博文也将从这3个角度出发。讲解一下Rust中的基本类型和逻辑规则
Rust基础数据类型
在Rust中的基础数据类型有两种: scalar
和 compound
Scalar Type
scalar的类型有:
- 有符号整数:
i8
,i16
,i32
,i64
,i128
andisize
(pointer size) - 无符号整数:
u8
,u16
,u32
,u64
,u128
andusize
(pointer size) - 浮点数:
f32
,f64
- char: Unicode scalar value like
'a'
,'α'
and'∞'
(每个字符4个字节) - bool:
true
orflase
- unit type:
()
,他是一个空的tuple,虽然unit type是一个tuple,但是它被认为是一个scalar因为它不包含其他类型。
这个地方我们需要留心unit type
, 后文中关于表达式的内容会涉及到。
Compound Type
这里介绍Rust中的两种Compound Type: Tuple
& Array
。Tuple
是不同类型数据的集合(与Struct有相似之处),Array
是相同数据的集合。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23// Tuple 类型可以将不同类型的变量放在一起
// 函数可以使用Tuple来返回多个值
fn tuple () {
let tup: (i32, f64, u8) = (500, 6.4, 1);
let tup = (500, 6.4, 1); // 编译器能够推断我们需要什么类型
// 解包
let (x, y, z) = tup;
// 也可以使用索引的形式访问
let five_hundred = tup.0;
let six_point_four = tup.1;
let one = x.2;
} // Tuple end
// Array: 存放在栈中,当我们想把数据存放在栈里时十分有用
// 但是Array只能存放相同类型的变量
fn array () {
let a = [1, 2, 3, 4, 5];
let index = 2;
let element = a[index]; // 使用方括号来访问Array中的内容
println!("The value of element is {}", element);
}// Array end
表达式与语句
对表达式和语句的精确区分是Rust精准高效的一个体现。
Rust中的函数由一系列语句(statement
)和一个可选的结尾表达式(expression
)组成。与其他语言对表达式和语句的模糊对待不同,Rust是一个由表达式组成的编程语言,在语言设计中包含了大量的表达式的运用,因此在使用时需要多多注意。
- Statement(语句):指的是一个执行了特定的操作但是没有返回值得指令
- Expression(表达式):计算了一个值并将其返回
1
2
3
4
5
6let x = 6; // “6”是一个表达式
let y = {
let x = 3; // 表达式也可以是由`{}`
x + 1 // 包围起来的代码块
};
为了区分语句和表达式,可以通过末尾是否使用;
来加以区分。
Rust控制流
Rust也提供了一些跟流控制相关的机制,通常我们接触到的就是if
, while
, for
.
If表达式
Rust中也有If
关键字,对条件进行判断,选择不同的执行路径,在这里我们并不是像C++一样称为if语句,而是if 表达式。值得注意的是,和C/C++、Python之类语言不同,if的条件必须是bool类型。并且由于if
是一个表达式,我们可以通过if表达式的返回值来为变量赋值,这个操作和Python中的 x= a if condition else b
很类似。有Python编程经验的人一定非常熟悉。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// basic usage
fn main() {
let number = 3;
// contition must be bool type
// if number {
// println!("Which is not allow in Rust!");
// }
if number < 5 {
println!("condition was true");
} else {
println!("condition was false");
}
}
// multiple condition
fn main() {
let number = 6;
if number % 4 == 0 {
println!("number is divisible by 4");
} else if number % 3 == 0 {
println!("number is divisible by 3");
} else if number % 2 == 0 {
println!("number is divisible by 2");
} else {
println!("number is not divisible by 4, 3, or 2");
}
}
// if statement
fn main() {
let condition = true;
let number = if condition {
5
} else {
6
//! we shouldn't use "six" here cause the type of `number` depends on condition
//! compiler will reject this behavior;
// "six"
};
println!("The value of number is: {}", number);
}
上面代码中展示了if
的一些基本用法,注意到第37行的注释,使用if表达式为变量赋值,if
的每一个分支的表达式返回值类型必须一样。
循环
Rust提供了3种类型的循环:loop, for, while
loop
表达式
loop
在Rust中充当着无限循环的角色,例如我们创建一个服务器,需要不断地从网卡中获取客户端发送的请求,loop
在这种场景下经常被使用。另外可以使用loop
加上break
表达式跳出循环并且返回某个表达式,后面再详细地说。
1 | fn main() { |
while
表达式
while
循环在其他编程语言中十分常见,用法也类似,一般用于可预测最终结果的循环。while
还有一个另外的用法,就是
while let Pattern = Expression
这个使用方法就是当 Pattern=Expression
这个条件满足的时候,就执行循环,当有一个条件不满足的时候就跳出循环。
1 | // basic usage of while |
for
表达式
for
表达式一般用来迭代某个容器,在Rust中这个是最常见的做法,也是for
表达式出现最多的地方。1
2
3
4
5
6
7
8// usage of for
fn main() {
let mut sum = 0;
for n in 1..11 {
sum += n;
}
assert_eq!(sum, 55);
}
关于表达式
既然说到loop
,while
,for
都是表达式,那么他们返回什么值?这个需要分情况对待。
loop
loop
表示无限循环。既然表示无限循环了,表示那么一般情况下loop
的下一个表达式/语句是永远不会执行到的。除非和break表达式一起使用时才能够跳出循环,所以loop
和break
一起使用时,能够用于从loop中返回值。
break表达式
把break
表达式放在loop
这层级下来描述不是特别好,但是既然在loop
中讲到了break
,那么就一起将内容放在这里挤一挤。
和其他语言一样,break
一般用于循环体中的跳出,它不只用于loop
,还能用于while
和for
中。一般程序执行到break
以后,将会跳出循环体,while
和for
天然就是loop
、if
…else
…和break
的结合体。正由于这一点,在大家都是表达式这一点while
,for
与loop
表现得有一些不同。
1 | // return value from loop |
在这里, break
后的表达式的值成为loop
的返回值。所以result
的值为20,类型为i32(编译器推断)。
值得注意的是, 我们可以在loop
里面有多个if
判断,然后有多个break
表达式,但是这几个break
表达式返回的类型必须一致,这样子编译器才能够确定result
的类型。在break
后也可以不带任何表达式,此时loop
表达式返回的是unit type
也就是 ()
。也就是说loop
表达式能够返回值的,表达式的叫法实至名归。
说到这里 while
和 for
也想给他们自己正名。上文说到的 “while
和for
天然就是loop
、if
…else
…和break
的结合体”,并且“break
后如果不带任何的表达式,loop
返回的是 unit type
”。所以 while
和 for
也是表达式,并且他们的返回值就是unit type
,我们可以看做编译器帮我们添加了一个后面不带表达式的break表达式,并且由于各个break
表达式块的返回类型必须相等,因此我们在while
和for
循环中就只能使用break
而不能在后面添加任何的表达式,或者直接在while
和for
程序块末尾使用非unit type
的表达式也是不被允许的。
1 | fn main() { |
上述代码只用for
表达式的运行结果来展示,while
表达式各位请自行验证。
至此,循环控制模块都是表达式这一点被证实了。
循环label:嵌套块跳转
C/C++中嵌套循环的跳出是一个比较麻烦的过程,Rust吸取了Java中类似的做法,支持给循环增加label命名通过在break
/continue
背后指定label的形式跳出到指定的循环嵌套模块。'foo: loop { break 'foo; }
, 'bar: while false {}
, 'humbug: for _ in 0..0 {}
1 | 'outer: loop { |