来自Introduction to Ada—If expressions:
Ada的
if
表达式类似于if
语句。但是,有一些差异源于它是一个表达式:所有分支的表达式必须是相同的类型
如果周围的表达式尚未包含括号,则必须用括号括起来
除非
else
后面的表达式具有布尔值,否则必须使用then
分支。在这种情况下,else分支是可选的,如果不存在,则默认为else True
。
我不明白需要使用if
关键字构建代码的两种不同方法。这背后的原因是什么?
还有case
表达式和case
语句。为什么是这样?
我认为引用Ada 2012 Rationale Chapter 3.1可以得到最佳答案:
WG9指导文件[1]确定需要注意的关键领域之一是提高编写和执行合同的能力。这些在前一章中有详细讨论。在为前置条件,后置条件,类型不变量和子类型谓词定义新方面时,很明显,如果没有更灵活的表达形式,则需要引入许多函数,因为在所有情况下,方面都是由表达式给出的。然而,声明一个函数并因此在函数体中给出条件,不变量或谓词的细节使得合同的细节对于人类读者来说相当遥远。信息隐藏通常是一件好事,但在这种情况下,它只是引入了默默无闻。引入了四种形式,即表达式,案例表达式,量化表达式和表达式函数。它们共同为Ada提供了一种功能性语言的灵活感受。
此外,if
语句和case
语句通常为所有分支中的同一变量分配不同的值,而不是其他:
if Foo > 10 then
Bar := 1;
else
Bar := 2;
end if;
在这种情况下,if
表达式可以提高可读性,并在代码中更清楚地说明正在发生的事情:
Bar := (if Foo > 10 then 1 else 2);
我们现在可以看到,代码的维护者不再需要读取整个if
语句,以便看到只更新了一个变量。
同样适用于case
表达式,这也可以减少嵌套if
表达式的需要。
另外,我可以回答你的问题:除了if语句之外,为什么基于C的语言还有三元运算符?:
?
Egilhh已经涵盖了主要原因,但实现表达式有时还有其他有用的理由。有时您只需要一个或两个方法来制作包,它们是制作包体的唯一原因。您可以使用表达式来创建表达式函数,以允许您在spec文件中定义操作。
此外,如果您最终得到一些复杂的变体记录组合,有时候表达式可用于在通常无法干净利落的情况下为它们设置默认值。请考虑以下示例:
with Ada.Text_IO; use Ada.Text_IO;
procedure Hello is
type Binary_Type is (On, Off);
type Inner(Binary : Binary_Type := Off) is record
case Binary is
when On =>
Value : Integer := 0;
when Off =>
null;
end case;
end record;
type Outer(Some_Flag : Boolean) is record
Other : Integer := 32;
Thing : Inner := (if Some_Flag then
(Binary => Off)
else
(Binary => On, Value => 23));
end record;
begin
Put_Line("Hello, world!");
end Hello;
我有一些更复杂的设置,旨在映射到硬件级别的复杂消息传递接口。尽可能使用默认值很好。现在我已经冷静地使用了Outer中的一个案例,但是我不得不为每个案例提供两个单独命名的消息字段版本,当你希望你的代码映射到ICD时,这真的不是最佳的。同样,我本可以使用一个函数来初始化它,但正如其他海报回答中所述,这并不总是一个好方法。
另一个概述了向Ada添加条件表达式的动机的地方可以在ARG文档AI05-0147-1中找到,它解释了动机并给出了一些使用示例。
我发现它们非常有用的地方的一个示例是处理命令行参数,例如,如果在命令行中未指定参数,则使用默认值。通常,您希望在一个程序中将这些值声明为常量。条件表达式使得更容易实现。
with Ada.Command_Line; use Ada;
procedure Main
is
N : constant Positive :=
(if Command_Line.Argument_Count = 0 then 2_000_000
else Positive'Value (Command_Line.Argument (1)));
...
否则,没有条件表达式,为了达到相同的效果,你需要声明一个我觉得更难读的函数;
with Ada.Command_Line; use Ada;
procedure Main
is
function Get_N return Positive is
begin
if Command_Line.Argument_Count = 0 then
return 2_000_000;
else
return Positive'Value (Command_Line.Argument (1));
end if;
end Get_N;
N : constant Positive := Get_N;
...