Rust语言入门教程(五) - 流控制语句
if 表达式
在Rust中, if语句的判断条件不需要用( )
括起来, 它会认为所有在if
和 {
之间的表达式就是判断条件,例如:
if num == 5 {
msg = "five";
}
判断条件的表达式必须返回一个bool
型的值, 因为Rust是一个不喜欢进行强制类型转换的语言,绝大多数时候, Rust都不会对数据进行强制类型转换,也就是说,下面的例子是一个错误的范例:
if 1 {
msg = "five"
}
如果要进行多分支的条件判断,可以使用else if
(注意 else
和if
是分开的),最后也可以用else
结尾, 例如:
if num == 5{
msg = "five";
} else if num == 4 {
msg = "four";
} else {
msg = "other";
}
注意, if
是一种表达式, 而不是语句。 语句不会返回值, 而表达式会返回值, 因此,上面的代码可以改写成这样:
msg = if num == 5{
"five"
} else if num == 4 {
"four"
} else {
"other"
}; // 注意, 这是一个赋值语句, 语句应以 ; 结尾
注意,在上面的例子中,每个判断分支的结尾没有;
, 因为这是一个尾部表达式, 用于给if表达式返回一个值;我们也不能使用return
关键字, 而只能使用尾部表达式,因为return
只能用于函数定义的代码块中,给函数返回结果;另外,每个判断分支返回的值的数据类型必须相同, 否则Rust编译器无法确定变量msg
的数据类型; 在if表达式的最后有一个;
, 因为整体来看, 这是一个赋值语句, 把if表达式的返回值赋值给了变量msg
, 而Rust的语句应该以;
结尾。
三元表达式?
Rust中没有三元表达式的设计, 例如在C语言中, 三元表达式形如:
num = a ? b : c;
虽然这种写法确实简单快捷, 但是即便这种简单的例子,其实也并不是特别易读和一目了然。如果事情稍微变得复杂一些, 加上一些三元表达式的嵌套, 看起来就更加的令人困惑了,比如:
num = a ? x ? y : z : c;
在Rust中我们选择抛弃三元表达式, 因为用if就已经能够简单的表达需求了, 比如:
num = if a {b} else {c};
即使存在一些嵌套也是比较简单易读的,
num = if a {
if x {y} else {z}
} else {
c
}
loop 循环
loop
是无条件的循环, 与变量不可变
的原因类似, Rust的这个设计的初衷, 也是考虑到编译器如果确定一个循环式无条件执行的情况下, 可以做更多的优化,从而获得更好的性能。
当然, 正如变量也需要改变,循环最终仍然是需要终结的。在Rust中,我们也使用break
语句来跳出循环,例如:
loop {
break;
}
但是如何跳出多层循环呢,比如:
loop {
loop {
loop {
break;
}
}
}
默认情况下, 这只会跳出最内层的循环,如果我想跳出指定层级的循环应该怎么办呢?Rust允许我们给循环打标签,以便满足我们提到的这种需求, 标签的格式是'标签名
(以一个'
开头), 下面的例子展示了如何从让break语句跳出指定的循环:
'bob: loop {
loop {
loop {
break 'bob;
}
}
}
最外层的循环被打上了一个名为'bob
的标签, 而break 'bob
语句告诉我们, 要跳出的正是这个'bob
循环。与break
的用法类型,continue
语句通常用于跳过本次循环,进入到下一次循环, continue
同样可以指定一个标签, 告诉代码下一次循环的入口在哪里, 例如:
'bob: loop {
loop {
continue 'bob;
}
}
while 循环
while
循环的行为和loop
基本一致, 只是每次进行循环前, 都会进行条件判断, 当条件判断表达式的返回值为true
时, 才会继续进行下一轮循环。 与if表达式的条件判断一样, 条件判断表达式的返回值必须为bool
型, Rust不会为其他类型的返回值进行强制类型转换。格式如下:
while dizzy() {
do_stuff()
}
用loop加上if, 也可以很容易的改写while表达式:
loop {
if !dizzy() {break}
do_stuff()
}
不要觉得这样做是不是因为我太无聊了,Rust中并没有do while
的设计, 用上面的改写方法, 就可以轻松的实现do while
的效果了:
loop {
do_stuff()
if !dizzy() {break}
}
for 循环
和大多数现代编程语言一样, Rust中的for
循环会遍历一个可迭代对象中的每个值。复合数据类型和集合数据类型(collections)通常都会有一些方法来返回一个可迭代对象,用于for
循环使用。
for num in [7, 8, 9].iter(){
// do stuff with num
}
上面的例子中[7, 8, 9]这个数组调用了iter()
函数来获取了一个迭代器,iter()
这个函数也是通用的获取迭代器的方法。一些有序的数据类型的迭代器会有序的返回一组值, 但一些无序的数据类型的迭代器返回的值的顺序就是随机的了。
Rust的for循环中, 如果迭代器返回的是一组值, 那么for循环中也可以用一组变量来直接解构并接收返回的值,例如:
let a = [(1, 2), (3, 4)];
for (x, y) in a.iter() {
// do stuff with x, y
}
还有一个常见的场景是在某个数字范围内进行for循环, 指定数字范围的格式是起始(闭)..结束(开)
:
for num in 0..50 {
// do stuff with num 1 to 49
}
如果想要包含结束的数字, 那么可以用这种格式起始(闭)..=结束(闭)
for num in 0..=50 {
// do stuff with num 1 to 50
}
小结
本章介绍了if条件判断语句, 和几种循环语句的格式和使用场景, 下一章将介绍Rust中比较重要的一种数据类型,String。