条件
if
// if condition == true { statement_01; }
// if true { expression_01 }
fn main(){
if true { print!("直接输出")}
}
fn main(){
if 1 == 1 { print!("直接输出")}
}
fn main(){
if 5 > 1 { print!("直接输出")}
}
//-->直接输出
// 注意,{ } 内部结束没有 分号; ,说明不是一个语句,但是编译器并不认为这是一个错误。
// 结果和 if true { print!("直接输出");} 加上分号变为语句一致。
// 因此可以认为,{ } 体内可以是语句,也可以是表达式。
// 当是表达式的时候,应当有返回值。很明显,print!宏是有返回值的。
// macro_rules! print { ($($arg : tt) *) => { ... }; }
// if condition {statement_01; } else{statement_02; }
// if condition {expression_01 } else{expression_02 }
// if condition {expression_01 } else{statement_02; }
fn main(){
let a = 1;
let b = 5u8;
if b > a {print!("b > a")}
else {println!("b <= a")}
}
// if后跟逻辑表达式,根据返回逻辑值 true 或者 false 执行后面大括号内的语句或者表达式.
// 注意,if 大括号后并无符号,直接跟随else及大括号.
// if condition_1 { } else if condition_2 { } else { }
if true { statement_01; }
else if true { statement_02; } // else if 可重复多遍
else{ statement_03; }
if true { statement_01; }
else if true { statement_02; } // else if 可重复多遍
else{ statement_03; }
if true { statement; }
else if true { expression } // else if 可重复多遍
else{ statement;}
fn main(){
let a = 5;
let b = 5u8;
if b > a { println!("b > a")}
else if b < a {println!("b < a")}
else { println!("b = a")}
}
// b = a
注:
- if Expressions:条件condition是表达式expression,而且是 逻辑表达式。逻辑运算的结果只有 true 和 false【不同于算数表达式,算数表达式的数学运算,结果是Number类型的数字,而非布尔值;python中 0 等同于 False,而Rust中不是】;因为Rust 是 静态类型(statically typed)语言,编译器会自动推导类型,但是不会自动转换类型。不会像JavaScript和python一样,自动将非布尔值转换。如果想像JavaScript和python一样,将数学表达式运用或非布尔类型变量 non-Boolean types用于if,需要通过 expression != 0 改为逻辑表达式使其值为布尔值。
- 判断条件 condition 没有用小括号包裹,和C语言以及JavaScript语言不同。可能因为表达式值只是 true 或 false,不会是字符串等其他类型,不会像语句如 return something 还需要判断返回值类型,定义及表达明确,所以不需要小括号。python也是不需要小括号,但是python会自动转换类型数值。Rust这点更明确清晰。
循环
for 循环
fn main(){
for i in 1..=9{
for j in 1..=i{
print!("{0} * {1} = {2} ",j,i,i*j);
}
println!();
}
}
// 1 * 1 = 1
// 1 * 2 = 2 2 * 2 = 4
// 1 * 3 = 3 2 * 3 = 6 3 * 3 = 9
// 1 * 4 = 4 2 * 4 = 8 3 * 4 = 12 4 * 4 = 16
// 1 * 5 = 5 2 * 5 = 10 3 * 5 = 15 4 * 5 = 20 5 * 5 = 25
// 1 * 6 = 6 2 * 6 = 12 3 * 6 = 18 4 * 6 = 24 5 * 6 = 30 6 * 6 = 36
// 1 * 7 = 7 2 * 7 = 14 3 * 7 = 21 4 * 7 = 28 5 * 7 = 35 6 * 7 = 42 7 * 7 = 49
// 1 * 8 = 8 2 * 8 = 16 3 * 8 = 24 4 * 8 = 32 5 * 8 = 40 6 * 8 = 48 7 * 8 = 56 8 * 8 = 64
// 1 * 9 = 9 2 * 9 = 18 3 * 9 = 27 4 * 9 = 36 5 * 9 = 45 6 * 9 = 54 7 * 9 = 63 8 * 9 = 72 9 * 9 = 81
循环变量
for 循环新建循环变量 i,假如 i 循环体外部有同名变量 i ,则暂时 shadowing ,等循环体内部循环完毕后销毁,循环体外部变量值返回。 粗浅的说,循环体内部的循环变量与循环体外部的同名变量无关。
fn main(){
let a = 1;
let b = 10;
for a in 5..b {
println!("a value in for loop is {}",a);
}
println!("a value is {}",a);
}
//a value in for loop is 5
//a value in for loop is 6
//a value in for loop is 7
//a value in for loop is 8
//a value in for loop is 9
//a value is 1
fn main(){
let mut b = 10;
for a in 5..b {
print!("a value in for loop is {}; ",a);
println!("b value in for loop is {}",b);
b -= 1;
}
println!("b value is {}",b);
}
//a value in for loop is 5; b value in for loop is 10
//a value in for loop is 6; b value in for loop is 9
//a value in for loop is 7; b value in for loop is 8
//a value in for loop is 8; b value in for loop is 7
//a value in for loop is 9; b value in for loop is 6
//b value is 5
Runoob
Rust 条件语句
实例
fn main() {
let number = 3;
if number < 5 {
println!(“条件为 true”);
} else {
println!(“条件为 false”);
}
}
在上述程序中有条件 if 语句,这个语法在很多其它语言中很常见,但也有一些区别:首先,条件表达式 number < 5 不需要用小括号包括(注意,不需要不是不允许);但是 Rust 中的 if 不存在单语句不用加 {} 的规则,不允许使用一个语句代替一个块。尽管如此,Rust 还是支持传统 else-if 语法的:
实例
fn main() {
let a = 12;
let b;
if a > 0 {
b = 1;
}
else if a < 0 {
b = -1;
}
else {
b = 0;
}
println!(“b is {}”, b);
}
运行结果:
b 为 1
Rust 中的条件表达式必须是 bool 类型,例如下面的程序是错误的:
实例
fn main() {
let number = 3;
if number { // 报错,expected bool
, found integerrustc(E0308)
println!(“Yes”);
}
}
虽然 C/C++ 语言中的条件表达式用整数表示,非 0 即真,但这个规则在很多注重代码安全性的语言中是被禁止的。
结合之前章学习的函数体表达式我们加以联想:
if
这种语法中的 { block 1 } 和 { block 2 } 可不可以是函数体表达式呢?
答案是肯定的!也就是说,在 Rust 中我们可以使用 if-else 结构实现类似于三元条件运算表达式 (A ? B : C) 的效果:
实例
fn main() {
let a = 3;
let number = if a > 0 { 1 } else { -1 };
println!(“number 为 {}”, number);
}
运行结果:
number 为 1
注意:两个函数体表达式的类型必须一样!且必须有一个 else 及其后的表达式块。
控制流
根据条件是否为真来决定是否执行某些代码,以及根据条件是否为真来重复运行一段代码是大部分编程语言的基本组成部分。Rust 代码中最常见的用来控制执行流的结构是 if 表达式和循环。
if 表达式
if 表达式允许根据条件执行不同的代码分支。你提供一个条件并表示 「如果条件满足,运行这段代码;如果条件不满足,不运行这段代码。」
在 projects 目录新建一个叫做 branches 的项目,来学习 if 表达式。在 src/main.rs 文件中,输入如下内容:
文件名: src/main.rs
fn main() {
let number = 3;
if number < 5 {<br /> println!("condition was true");<br /> } else {<br /> println!("condition was false");<br /> }<br />}<br />所有的 if 表达式都以 if 关键字开头,其后跟一个条件。在这个例子中,条件检查变量 number 的值是否小于 5。在条件为真时希望执行的代码块位于紧跟条件之后的大括号中。if 表达式中与条件关联的代码块有时被叫做 arms,就像第二章 「比较猜测的数字和秘密数字」 部分中讨论到的 match 表达式中的分支一样。
也可以包含一个可选的 else 表达式来提供一个在条件为假时应当执行的代码块,这里我们就这么做了。如果不提供 else 表达式并且条件为假时,程序会直接忽略 if 代码块并继续执行下面的代码。
尝试运行代码,应该能看到如下输出:
$ cargo run
Compiling branches v0.1.0 (file:///projects/branches)
Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
Running target/debug/branches
condition was true
尝试改变 number 的值使条件为假时看看会发生什么:
let number = 7;
再次运行程序并查看输出:
$ cargo run
Compiling branches v0.1.0 (file:///projects/branches)
Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
Running target/debug/branches
condition was false
另外值得注意的是代码中的条件 必须 是 bool 值。如果条件不是 bool 值,我们将得到一个错误。例如,尝试运行以下代码:
文件名: src/main.rs
fn main() {
let number = 3;
if number {<br /> println!("number was three");<br /> }<br />}<br />这里 if 条件的值是 3,Rust 抛出了一个错误:
error[E0308]: mismatched types
—> src/main.rs:4:8
|
4 | if number {
| ^^^^^^ expected bool, found integral variable
|
= note: expected type bool
found type {integer}
这个错误表明 Rust 期望一个 bool 却得到了一个整数。不像 Ruby 或 JavaScript 这样的语言,Rust 并不会尝试自动地将非布尔值转换为布尔值。必须总是显式地使用布尔值作为 if 的条件。例如,如果想要 if 代码块只在一个数字不等于 0 时执行,可以把 if 表达式修改成下面这样:
文件名: src/main.rs
fn main() {
let number = 3;
if number != 0 {<br /> println!("number was something other than zero");<br /> }<br />}<br />运行代码会打印出 number was something other than zero。
使用 else if 处理多重条件
可以将 else if 表达式与 if 和 else 组合来实现多重条件。例如:
文件名: src/main.rs
fn main() {
let number = 6;
if number % 4 == 0 {<br /> println!("number is divisible by 4");<br /> } else if number % 3 == 0 {<br /> println!("number is divisible by 3");<br /> } else if number % 2 == 0 {<br /> println!("number is divisible by 2");<br /> } else {<br /> println!("number is not divisible by 4, 3, or 2");<br /> }<br />}<br />这个程序有四个可能的执行路径。运行后应该能看到如下输出:
$ cargo run
Compiling branches v0.1.0 (file:///projects/branches)
Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
Running target/debug/branches
number is divisible by 3
当执行这个程序时,它按顺序检查每个 if 表达式并执行第一个条件为真的代码块。注意即使 6 可以被 2 整除,也不会输出 number is divisible by 2,更不会输出 else 块中的 number is not divisible by 4, 3, or 2。原因是 Rust 只会执行第一个条件为真的代码块,并且一旦它找到一个以后,甚至都不会检查剩下的条件了。
使用过多的 else if 表达式会使代码显得杂乱无章,所以如果有多于一个 else if 表达式,最好重构代码。为此,第六章会介绍一个强大的 Rust 分支结构(branching construct),叫做 match。
在 let 语句中使用 if
因为 if 是一个表达式,我们可以在 let 语句的右侧使用它,例如在示例 3-2 中:
文件名: src/main.rs
fn main() {
let condition = true;
let number = if condition {
5
} else {
6
};
println!("The value of number is: {}", number);<br />}<br />示例 3-2:将 if 表达式的返回值赋给一个变量
number 变量将会绑定到表示 if 表达式结果的值上。运行这段代码看看会出现什么:
$ cargo run
Compiling branches v0.1.0 (file:///projects/branches)
Finished dev [unoptimized + debuginfo] target(s) in 0.30 secs
Running target/debug/branches
The value of number is: 5
记住,代码块的值是其最后一个表达式的值,而数字本身就是一个表达式。在这个例子中,整个 if 表达式的值取决于哪个代码块被执行。这意味着 if 的每个分支的可能的返回值都必须是相同类型;在示例 3-2 中,if 分支和 else 分支的结果都是 i32 整型。如果它们的类型不匹配,如下面这个例子,则会出现一个错误:
文件名: src/main.rs
fn main() {
let condition = true;
let number = if condition {<br /> 5<br /> } else {<br /> "six"<br /> };
println!("The value of number is: {}", number);<br />}<br />当编译这段代码时,会得到一个错误。if 和 else 分支的值类型是不相容的,同时 Rust 也准确地指出在程序中的何处发现的这个问题:
error[E0308]: if and else have incompatible types
—> src/main.rs:4:18
|
4 | let number = if condition {
| __^
5 | | 5
6 | | } else {
7 | | “six”
8 | | };
| |_^ expected integral variable, found &str
|
= note: expected type {integer}
found type &str
if 代码块中的表达式返回一个整数,而 else 代码块中的表达式返回一个字符串。这不可行,因为变量必须只有一个类型。Rust 需要在编译时就确切的知道 number 变量的类型,这样它就可以在编译时验证在每处使用的 number 变量的类型是有效的。Rust 并不能够在 number 的类型只能在运行时确定的情况下工作;这样会使编译器变得更复杂而且只能为代码提供更少的保障,因为它不得不记录所有变量的多种可能的类型。
使用循环重复执行
多次执行同一段代码是很常用的,Rust 为此提供了多种 循环(loops)。一个循环执行循环体中的代码直到结尾并紧接着回到开头继续执行。为了实验一下循环,让我们新建一个叫做 loops 的项目。
Rust 有三种循环:loop、while 和 for。我们每一个都试试。
使用 loop 重复执行代码
loop 关键字告诉 Rust 一遍又一遍地执行一段代码直到你明确要求停止。
作为一个例子,将 loops 目录中的 src/main.rs 文件修改为如下:
文件名: src/main.rs
fn main() {
loop {
println!(“again!”);
}
}
当运行这个程序时,我们会看到连续的反复打印 again!,直到我们手动停止程序。大部分终端都支持一个快捷键,ctrl-c,来终止一个陷入无限循环的程序。尝试一下:
$ cargo run
Compiling loops v0.1.0 (file:///projects/loops)
Finished dev [unoptimized + debuginfo] target(s) in 0.29 secs
Running target/debug/loops
again!
again!
again!
again!
^Cagain!
符号 ^C 代表你在这按下了 ctrl-c。在 ^C 之后你可能看到也可能看不到 again! ,这取决于在接收到终止信号时代码执行到了循环的何处。
幸运的是,Rust 提供了另一种更可靠的退出循环的方式。可以使用 break 关键字来告诉程序何时停止循环。回忆一下在第二章猜猜看游戏的 「猜测正确后退出」 部分使用过它来在用户猜对数字赢得游戏后退出程序。
从循环返回
loop 的一个用例是重试可能会失败的操作,比如检查线程是否完成了任务。然而你可能会需要将操作的结果传递给其它的代码。如果将返回值加入你用来停止循环的 break 表达式,它会被停止的循环返回:
fn main() {
let mut counter = 0;
let result = loop {<br /> counter += 1;
if counter == 10 {<br /> break counter * 2;<br /> }<br /> };
assert_eq!(result, 20);<br />}<br />while 条件循环<br />在程序中计算循环的条件也很常见。当条件为真,执行循环。当条件不再为真,调用 break 停止循环。这个循环类型可以通过组合 loop、if、else 和 break 来实现;如果你喜欢的话,现在就可以在程序中试试。
然而,这个模式太常用了,Rust 为此内置了一个语言结构,它被称为 while 循环。示例 3-3 使用了 while:程序循环三次,每次数字都减一。接着,在循环结束后,打印出另一个信息并退出。
文件名: src/main.rs
fn main() {
let mut number = 3;
while number != 0 {<br /> println!("{}!", number);
number = number - 1;<br /> }
println!("LIFTOFF!!!");<br />}<br />示例 3-3: 当条件为真时,使用 while 循环运行代码
这种结构消除了很多使用 loop、if、else 和 break 时所必须的嵌套,这样更加清晰。当条件为真就执行,否则退出循环。
使用 for 遍历集合
可以使用 while 结构来遍历集合中的元素,比如数组。例如,看看示例 3-4。
文件名: src/main.rs
fn main() {
let a = [10, 20, 30, 40, 50];
let mut index = 0;
while index < 5 {<br /> println!("the value is: {}", a[index]);
index = index + 1;<br /> }<br />}<br />示例 3-4:使用 while 循环遍历集合中的元素
这里,代码对数组中的元素进行计数。它从索引 0 开始,并接着循环直到遇到数组的最后一个索引(这时,index < 5 不再为真)。运行这段代码会打印出数组中的每一个元素:
$ cargo run
Compiling loops v0.1.0 (file:///projects/loops)
Finished dev [unoptimized + debuginfo] target(s) in 0.32 secs
Running target/debug/loops
the value is: 10
the value is: 20
the value is: 30
the value is: 40
the value is: 50
数组中的所有五个元素都如期被打印出来。尽管 index 在某一时刻会到达值 5,不过循环在其尝试从数组获取第六个值(会越界)之前就停止了。
但这个过程很容易出错;如果索引长度不正确会导致程序 panic。这也使程序更慢,因为编译器增加了运行时代码来对每次循环的每个元素进行条件检查。
作为更简洁的替代方案,可以使用 for 循环来对一个集合的每个元素执行一些代码。for 循环看起来如示例 3-5 所示:
文件名: src/main.rs
fn main() {
let a = [10, 20, 30, 40, 50];
for element in a.iter() {<br /> println!("the value is: {}", element);<br /> }<br />}<br />示例 3-5:使用 for 循环遍历集合中的元素
当运行这段代码时,将看到与示例 3-4 一样的输出。更为重要的是,我们增强了代码安全性,并消除了可能由于超出数组的结尾或遍历长度不够而缺少一些元素而导致的 bug。
例如,在示例 3-4 的代码中,如果从数组 a 中移除一个元素但忘记将条件更新为 while index < 4,代码将会 panic。使用 for 循环的话,就不需要惦记着在改变数组元素个数时修改其他的代码了。
for 循环的安全性和简洁性使得它成为 Rust 中使用最多的循环结构。即使是在想要循环执行代码特定次数时,例如示例 3-3 中使用 while 循环的倒计时例子,大部分 Rustacean 也会使用 for 循环。这么做的方式是使用 Range,它是标准库提供的类型,用来生成从一个数字开始到另一个数字之前结束的所有数字的序列。
下面是一个使用 for 循环来倒计时的例子,它还使用了一个我们还未讲到的方法,rev,用来反转 range:
文件名: src/main.rs
fn main() {
for number in (1..4).rev() {
println!(“{}!”, number);
}
println!(“LIFTOFF!!!”);
}
这段代码看起来更帅气不是吗?
总结
你做到了!这是一个大章节:你学习了变量、标量和复合数据类型、函数、注释、 if 表达式和循环!如果你想要实践本章讨论的概念,尝试构建如下程序:
相互转换摄氏与华氏温度。
生成 n 阶斐波那契数列。
打印圣诞颂歌 「The Twelve Days of Christmas」 的歌词,并利用歌曲中的重复部分(编写循环)。
当你准备好继续的时候,让我们讨论一个其他语言中 并不 常见的概念:所有权(ownership)。
————————————————
RustPrimer
控制流(control flow)
If
If是分支 (branch) 的一种特殊形式,也可以使用else
和else if
。 与C语言不同的是,逻辑条件不需要用小括号括起来,但是条件后面必须跟一个代码块。 Rust中的if
是一个表达式 (expression),可以赋给一个变量:
let x = 5;
let y = if x == 5 { 10 } else { 15 };
Rust是基于表达式的编程语言,有且仅有两种语句 (statement):
- 声明语句 (declaration statement),比如进行变量绑定的
let
语句。 - 表达式语句 (expression statement),它通过在末尾加上分号
;
来将表达式变成语句, 丢弃该表达式的值,一律返回unit()
。
表达式如果返回,总是返回一个值,但是语句不返回值或者返回()
,所以以下代码会报错:
let y = (let x = 5);
let z: i32 = if x == 5 { 10; } else { 15; };
值得注意的是,在Rust中赋值 (如x = 5
) 也是一个表达式,返回unit的值()
。
For
Rust中的for
循环与C语言的风格非常不同,抽象结构如下:
for var in expression {
code
}
其中expression
是一个迭代器 (iterator),具体的例子为0..10
(不包含最后一个值), 或者[0, 1, 2].iter()
。
While
Rust中的while
循环与C语言中的类似。对于无限循环,Rust有一个专用的关键字loop
。 如果需要提前退出循环,可以使用关键字break
或者continue
, 还允许在循环的开头设定标签 (同样适用于for
循环):
'outer: loop {
println!("Entered the outer loop");
'inner: loop {
println!("Entered the inner loop");
break 'outer;
}
println!("This point will never be reached");
}
println!("Exited the outer loop");
Match
Rust中的match
表达式非常强大,首先看一个例子:
let day = 5;
match day {
0 | 6 => println!("weekend"),
1 ... 5 => println!("weekday"),
_ => println!("invalid"),
}
其中|
用于匹配多个值,...
匹配一个范围 (包含最后一个值),并且_
在这里是必须的, 因为match
强制进行穷尽性检查 (exhaustiveness checking),必须覆盖所有的可能值。 如果需要得到|
或者...
匹配到的值,可以使用@
绑定变量:
let x = 1;
match x {
e @ 1 ... 5 => println!("got a range element {}", e),
_ => println!("anything"),
}
使用ref
关键字来得到一个引用:
let x = 5;
let mut y = 5;
match x {
// the `r` inside the match has the type `&i32`
ref r => println!("Got a reference to {}", r),
}
match y {
// the `mr` inside the match has the type `&i32` and is mutable
ref mut mr => println!("Got a mutable reference to {}", mr),
}
再看一个使用match
表达式来解构元组的例子:
let pair = (0, -2);
match pair {
(0, y) => println!("x is `0` and `y` is `{:?}`", y),
(x, 0) => println!("`x` is `{:?}` and y is `0`", x),
_ => println!("It doesn't matter what they are"),
}
match
的这种解构同样适用于结构体或者枚举。如果有必要,还可以使用..
来忽略域或者数据:
struct Point {
x: i32,
y: i32,
}
let origin = Point { x: 0, y: 0 };
match origin {
Point { x, .. } => println!("x is {}", x),
}
enum OptionalInt {
Value(i32),
Missing,
}
let x = OptionalInt::Value(5);
match x {
// 这里是 match 的 if guard 表达式,我们将在以后的章节进行详细介绍
OptionalInt::Value(i) if i > 5 => println!("Got an int bigger than five!"),
OptionalInt::Value(..) => println!("Got an int!"),
OptionalInt::Missing => println!("No such luck."),
}
此外,Rust还引入了if let
和while let
进行模式匹配:
let number = Some(7);
let mut optional = Some(0);
// If `let` destructures `number` into `Some(i)`, evaluate the block.
if let Some(i) = number {
println!("Matched {:?}!", i);
} else {
println!("Didn't match a number!");
}
// While `let` destructures `optional` into `Some(i)`, evaluate the block.
while let Some(i) = optional {
if i > 9 {
println!("Greater than 9, quit!");
optional = None;
} else {
println!("`i` is `{:?}`. Try again.", i);
optional = Some(i + 1);
}
}