Ada 编程/控制
条件语句
[编辑源代码]条件语句是只有当特定表达式(条件)为真时才会执行的代码块。
if-else
[编辑源代码]if-else 语句是最简单的条件语句。它们也被称为分支,因为当程序在执行过程中到达一个 if 语句时,控制会“分支”到两个或多个“方向”中的一个。if-else 语句通常具有以下形式
if
conditionthen
statement;else
other statement;end
if
;
如果原始条件满足,则第一个语句中的所有代码都将被执行。可选的 else 部分指定一个备用语句,该语句将在条件为假时执行。不同编程语言的语法会有所不同,但大多数编程语言(特别是过程式 和结构化 语言)都内置了某种形式的 if-else 条件语句。if-else 语句通常可以扩展为以下形式
if
conditionthen
statement;elsif
conditionthen
other statement;elsif
conditionthen
other statement; ...else
another statement;end
if
;
整个代码块中只执行一个语句。这个语句将是第一个其条件计算结果为真的语句。使用示例可以更容易理解 if-else-if 结构的概念
with
Ada.Text_IO;use
Ada.Text_IO; ...type
Degreesis
new
Floatrange
-273.15 .. Float'Last; ... Temperature : Degrees; ...if
Temperature >= 40.0then
Put_Line ("Wow!"); Put_Line ("It's extremely hot");elsif
Temperature >= 30.0then
Put_Line ("It's hot");elsif
Temperature >= 20.0then
Put_Line ("It's warm");elsif
Temperature >= 10.0then
Put_Line ("It's cool");elsif
Temperature >= 0.0then
Put_Line ("It's cold");else
Put_Line ("It's freezing");end
if
;
优化提示
[编辑源代码]当此程序执行时,计算机将按顺序检查所有条件,直到其中一个条件与其对真的概念匹配。一旦发生这种情况,程序将执行紧随条件之后的语句并继续,而不会检查任何其他条件。出于这个原因,当您尝试优化 程序时,最好按降序概率对 if-else 条件进行排序。这将确保在最常见的情况下,计算机需要做更少的工作,因为它很可能只需要检查一两个“分支”就能找到它应该执行的语句。但是,在第一次编写程序时,尽量不要过多地考虑这个问题,以免您发现自己进行了过早优化。
话虽如此,您应该知道,一个优化编译器可能会随意重新排列您的 if 语句,前提是该语句没有副作用。在其他技术中,优化编译器甚至可能应用跳转表 和二分搜索。
在 Ada 中,默认情况下,具有多个条件的条件语句不使用短路求值。为了模拟 C/C++ 的短路求值,在条件之间使用
或and
then
。or
else
case
[编辑源代码]通常需要将一个特定变量与几个常量表达式进行比较。对于这种条件表达式,存在 case 语句。例如
case
Xis
when
1 => Walk_The_Dog;when
5 => Launch_Nuke;when
8 | 10 => Sell_All_Stock;when
others
=> Self_Destruct;end
case
;
X 的子类型必须是离散类型,即枚举类型或整数类型。
在 Ada 中,case 语句的一个优点是编译器将检查选择的覆盖率,即变量 X 的子类型的所有值都必须存在,或者存在一个默认分支when
others
必须指定在其余情况下该怎么做。
无条件语句
[编辑源代码]无条件语句允许您更改程序的流程,而无需条件。使用无条件语句时要小心。它们通常会使程序难以理解。阅读goto 有害吗? 获取更多信息。
return
[编辑源代码]结束一个函数并返回到调用过程或函数。
对于过程
return
;
对于函数
return
Value;
goto
[编辑源代码]Goto 将控制权转移到标签之后的语句。
goto
Label;
Dont_Do_Something;
<<Label>>
...
goto 有害吗?
[编辑源代码]自从迪克斯特拉教授发表了Go To Statement Considered Harmful,goto 在结构化编程语言中被认为是不好的做法,实际上,许多编程风格指南禁止使用 goto 语句。但人们经常忽略的是,任何不是过程或函数中最后一个语句的 return 也是一个无条件语句——一个伪装的 goto。不过,有一个重要的区别:return 是一种仅向前使用的 goto。异常也是一种 goto 语句;请注意,它们不需要指定将要跳转到的位置。
因此,如果您有包含多个 return 语句的函数和过程,那么您就像使用 goto 一样破坏了程序的结构。实际上,几乎每个程序员都熟悉 'return' 语句及其关联的行为;因此,在可读性方面,以下两个示例几乎相同
还要注意,Ada 中的 goto 语句比其他语言中的更安全,因为它不允许您将控制权转移
- 到代码块之外;
- 在 case 语句、if 语句或 select 语句的备选方案之间;
- 在不同的异常处理程序之间;或者从处理的语句序列的异常处理程序返回到其语句序列。
procedure
Use_Returnis
begin
Do_Something;if
Testthen
return
;end
if
; Do_Something_Else;return
;end
Use_Return;
procedure
Use_Gotois
begin
Do_Something;if
Testthen
goto
Exit_Use_Goto;end
if
; Do_Something_Else; <<Exit_Use_Goto>>return
;end
Use_Goto;
由于使用 goto 需要声明一个标签,因此 goto 实际上比使用 return 可读性高两倍。因此,如果您关注的是可读性,而不是严格的“不要使用 goto”编程规则,那么您应该使用 goto 而不是多个 return。当然,最好的方法是结构化方法,在这种方法中既不需要 goto 也不需要多个 return
procedure
Use_Ifis
begin
Do_Something;if
not
Testthen
Do_Something_Else;end
if
;return
;end
Use_If;
循环
[编辑源代码]循环允许您一遍又一遍地重复一组语句。
无限循环
[编辑源代码]无限循环是一个永不结束的循环,循环内的语句会永远重复。术语“无限循环”是一个相对术语;如果正在运行的程序因程序控制范围之外的某些原因而强制终止,则无限循环确实会结束。
Endless_Loop :loop
Do_Something;end
loop
Endless_Loop;
循环名称(在本例中为“Endless_Loop”)是 Ada 的一个可选功能。命名循环对于可读性很好,但不是严格必需的。但是,如果程序应该跳出内部循环,循环名称很有用,请参见下文。
循环条件在开头
[编辑源代码]此循环在开头有一个条件。只要条件满足,语句就会重复执行。如果条件在一开始就不满足,则循环内的语句永远不会被执行。
While_Loop :while
X <= 5loop
X := Calculate_Something;end
loop
While_Loop;
循环条件在结尾
[编辑源代码]此循环在结尾有一个条件,语句会重复执行,直到条件满足。由于检查在结尾,因此语句至少执行一次。
Until_Loop :loop
X := Calculate_Something;exit
Until_Loopwhen
X > 5;end
loop
Until_Loop;
循环条件在中间
[编辑源代码]有时你需要先进行计算,并在满足特定条件时退出循环。但如果条件不满足,则需要执行其他操作。因此你需要一个退出条件位于中间的循环。
Exit_Loop :loop
X := Calculate_Something;exit
Exit_Loopwhen
X > 5; Do_Something (X);end
loop
Exit_Loop;
在 Ada 中,exit 条件可以与任何其他循环语句结合使用。你也可以拥有多个 exit 语句。你也可以在多个循环嵌套的情况下,退出命名为外层循环。
for 循环
[编辑源代码]很多时候,你需要一个循环,其中一个特定变量从给定的起始值向上或向下计数到特定结束值。你可以在此处使用 while 循环——但由于这是一种非常常见的循环,因此提供了一种更简单的语法。
For_Loop :for
Iin
Integerrange
1 .. 10loop
Do_Something (I)end
loop
For_Loop;
你不必像示例中那样声明子类型和范围。如果你省略子类型,则编译器将根据上下文确定它;如果你省略范围,则循环将遍历给定子类型的每个值。
与 Ada 一样,当“根据上下文确定”给出两个或多个可能的选项时,将显示错误消息,然后你必须指定要使用的类型。Ada 仅在安全的情况下进行“猜测”。
循环计数器 I 是一个隐式声明的常量,在循环体结束后将不再存在。
数组上的 for 循环
[编辑源代码]另一种非常常见的情况是需要一个循环来遍历数组的每个元素。以下示例代码展示了如何实现这一点。
Array_Loop :for
Iin
X'Rangeloop
X (I) := Get_Next_Element;end
loop
Array_Loop;
其中 X 是一个数组。注意:这种语法主要用于数组(因此得名),但也可以在需要完整迭代的其他类型上使用。
以下示例展示了如何遍历整数类型的每个元素。
with
Ada.Text_IO;procedure
Range_1is
type
Range_Typeis
range
-5 .. 10;package
T_IOrenames
Ada.Text_IO;package
I_IOis
new
Ada.Text_IO.Integer_IO (Range_Type);begin
for
Ain
Range_Typeloop
I_IO.Put (Item => A, Width => 3, Base => 10);if
A < Range_Type'Lastthen
T_IO.Put (",");else
T_IO.New_Line;end
if
;end
loop
;end
Range_1;
- 5.3: if 语句 [带注释的]
- 5.4: case 语句 [带注释的]
- 5.5: loop 语句 [带注释的]
- 5.6: 块语句 [带注释的]
- 5.7: exit 语句 [带注释的]
- 5.8: goto 语句 [带注释的]
- 6.5: return 语句 [带注释的]