在本章中,我们将介绍控制流,如何让你的代码有条件地执行,以及在需要时重复执行。
简介
在本章中,你将:
- 使用if、else和else if在你的代码中创建不同的执行路径。
- 应用循环来重复语句。
- 在循环中添加条件,以中断或跳过迭代。
- 迭代数据集合。
用if 创建一个新的执行路径
让我们考虑一下这组语句。
let salary = 220.2;
let other_income = 10.5;
let tax = 0.2; // percentage
let takehome_salary = (salary + other_income) * (1 as f32 - tax);
上面我们有一个关于某人工资的计算。想象一下,虽然某人的收入低于一定的收入水平,就可以免于纳税,那么怎么办?
对于这种情况,我们可以用一个if 结构来表达这个条件。
我们的代码现在可以这样表达。
let no_tax_value = 300.0;
let salary = 220.2;
let other_income = 10.5;
let tax = 0.2; // percentage
let mut takehome_salary = salary + other_income;
if (salary + other_income) > no_tax_value {
takehome_salary = (salary + other_income) * (1 as f32 - tax); // tax deducted
}
if 子句评估了一个表达式(salary + other_income) > no_tax_value ,如果评估为true ,将运行括号内的代码。如果表达式的值为false ,那么该语句将不会被运行。
你的程序现在有两个不同的执行路径,取决于salary + other_income 的总和。
否则,如果if 是假的会怎样?
你可以用一个else 来扩展你的if ,如果if 的值为false,就会运行。
在这个例子中,一个客户试图从他们的账户中提取一个金额,如果它不能完成,就会显示一个错误信息。
let mut account_balance = 100.0;
let amount = 101.50;
if account_balance - amount > 0 as f32 {
account_balance -= amount;
} else {
println!("Can't withdraw {}", amount);
}
从上面看,else 是紧挨着if 。事实上,没有if ,它就不能存在。
Else if,如果你有一个以上的条件
到目前为止,你已经看到了if 和else ,但还有一个结构else if ,我们可以使用。else if 的意思是,如果if 的评估值为false ,就执行。你可以有任何数量的else if 。下面是如何使用它。
let card_number = 11;
if card_number == 11 {
println!("Jack");
} else if card_number == 12 {
println!("Queen");
} else if card_number == 13 {
println!("King")
} else if card_number == 14 || card_number == 1 {
println!("Ace");
} else {
println!("Card number is {}", card_number);
}
正如你在上面看到的,我们可以在最初的if 之后添加一些else if 结构。
if 作为一个表达式
外面的许多语言都有所谓的三元表达式。这意味着在同一行中,一个值被分配给一个变量。下面是它在其他语言中的样子。
// javascript
let salary = 100;
let tax = 0.2;
let take_home_salary = salary > 200 ? salary * (1 as f32 - tax) : salary;
其价值在于不必用大括号定义一个if ,这可能会占用几行。然而,Rust可以这样做,像这样。
let salary = 100.0;
let tax = 0.2;
let take_home_salary = if salary > 200.0 { salary * (1.0 - tax) } else {salary};
println!("Salary is {}", take_home_salary);
注意if 和else 里面的代码没有分号; ,这使得它们成为表达式。所以这里你使用的是基于表达式的if 和else 。
循环
当你想重复一个语句若干次时,就会用到循环。例如,这可能是。
- 基于命令的程序,你要求用户输入,直到他们选择退出该程序
- 迭代的东西。
- 一个东西的集合,例如 "订单 "和处理每个订单
- 对一个目录中的文件进行迭代。
正如你所看到的,有很多情况下,循环一组语句是有意义的。Rust为我们提供了许多循环的方法。
loop, 循环语句
使用这种结构,你可以永远重复语句,或者直到程序关闭。下面是示例代码。
loop {
println!("forever");
}
用break中断一个循环
不过你可以通过给它添加一个break ,来中断循环机制。考虑一下下面的代码,看看它是如何工作的。
let repeat_times: i32 = 5;
let mut index = 0;
loop {
if index == repeat_times {
break;
}
println!("Loop {}", index + 1);
index += 1;
}
这个程序将打印以下内容。
Loop 1
Loop 2
Loop 3
Loop 4
Loop 5
前面的代码将打印 "永远",直到你退出程序。
从循环中返回
当你用break 语句退出一个循环时,可以从该循环中返回一个值。
下面是你如何写的。
let mut points = 0;
let result = loop {
if points >= 10 {
break points;
}
points += 2;
}
这里,points ,每一次迭代都会递增。一旦中断条件为真,points 的当前值将被返回到break points ,并且该值被分配到result 。
虽然
到目前为止,你已经看到了如何使用loop ,并在其中定义条件,然后调用break 来退出循环。使用while ,你可以将中断条件定义为定义while 的一部分,像这样。
let mut points = 0;
while points < 10 {
points += 2;
}
println!("Value of points is {}", points);
这里,你的中断条件被定义在while 关键字之后。没有必要使用if 或break 关键字来退出循环。
哪个版本最容易阅读,
loop还是while?
迭代一个集合
想要重复一个语句的一个常见原因是处理具有序列特征的东西。例如,它可以是。
- 游泳比赛中的积分列表
- 购物篮中的一组物品
要定义一个列表,我们可以使用以下语法。
let judges_result = [8, 7, 8, 9, 9];
要在一个列表中列出特定的项目,我们使用方括号,[] 和一个介于0和列表长度-1之间的数字。在上面的例子中,0,1,2,3,4是可寻址的索引。这里有一个例子。
judges_result[2]; //8
试图用索引5访问,会导致错误。
迭代
那么,我们如何通过iterates_result 迭代?有两种方法我们可以使用。
while, 使用while,这是完全可以的,但是,我们需要跟踪什么时候停止迭代,因为我们可能最终出界。for in.使用这种结构,只要列表中还有项目,我们就可以保证只列出项目。
让我们尝试一下使用while的第一个变体。
let judges_result = [8, 7, 8, 9, 9];
let mut index = 0;
while index < 5 {
println!("Judge: {0} is {1} ", index + 1, judges_result[index]);
}
现在,让我们把它与使用for in 。
let judges_result = [8, 7, 8, 9, 9];
for vote in judges_result {
println!("Judge: {} ", vote);
}
等等,这不是一个公平的比较,索引怎么了?
为了得到索引,我们需要使用一个稍微复杂的结构。
for (i, vote) in judges_result.iter().enumerate() {
println!("Judge: {0} is {1} ", index + 1, vote);
}
这里发生的情况是,我们调用iter() ,然后再调用enumerate() 。现在我们可以访问一个元组,其中包含索引,i 和我们的值,vote 。
提醒:元组是一种复杂的数据类型,通过添加小括号和逗号来分隔数值,像这样创建。
fn create_tuple(a: i32, b: i32) -> (i32, i32) {
(a, b)
}
let (a,b) = create_tuple(2, 4);
println!("{0} {1}", a, b);
赋值
想象一下,有人从CSV文件中读取POS(销售点系统)今天的条目到一个数组entries 。现在打印出购买的总额和平均价值。
信息:如果里面有一个低于0的值,就应该抛出一个方法,因为这是读取输入时的一个错误。
下面是运行该程序的情况。
Here's today's purchases:
33.5, 7.25, 15.5, 44.9
The total is: 101.15
The average purchase was: 25.2875
解决方案
fn main () {
let entries = [33.5, 7.25, 15.5, 44.9, -1.0];
let mut total:f32 = 0.0;
let mut approved_entries = 0;
println!("Today's entries are");
for item in entries {
if item < 0 as f32 {
continue;
}
total += item;
print!("{},", item);
approved_entries += 1;
}
print!("\n");
println!("The total is {}", total);
println!("The average purchase was {}", total / approved_entries as f32);
}