Ada 是否有任何关于何时使用函数与带有输出参数的过程的惯用规则?

Rod*_*deo 4 ada

您可以通过让函数返回一个值来分配给变量:

My_Int : Integer := My_Math_Func [(optional params)];

或者你可以用一个程序来做到这一点(假设My_Int已经声明了):

My_Math_Proc ([optional params;] [in] out My_Int);

显然,一个过程不能像第一个例子中的函数那样初始化一个变量,但我希望有一些具体的、实用的规则来说明何时以及为什么选择一个。

Bri*_*ond 8

两个让你开始......

当要返回多个结果时,具有多个 OUT 参数的过程通常是一个不错的选择。

如果在子程序调用之前不知道对象的大小,则不能使用 OUT 参数,因为它必须准确地声明为正确的大小,但函数返回可以通过初始化调用者中的变量来设置大小。这通常与在 Declare 块中声明的变量一起使用,它可以在每次调用时保存不同大小的字符串。

此示例显示了通过调用Read_File函数初始化的变量“text” ,以在循环的每次迭代中保存不同文件的内容。安全,不需要“malloc”或“free”或指针。(Filename在这个例子中是一个文件名数组)

for i in 1 .. last_file loop
   declare
      text : String := Read_File(Filename(i));
      -- the size of "text" is determined by the file contents
   begin
      --   process the text here. 
      for j in text'range loop
         if text(j) = '*' then 
         ...
      end loop;
   end
end loop;
Run Code Online (Sandbox Code Playgroud)

编辑:我想我最好提及基本的数学原理,因为与许多其他语言相比,Ada 更接近于数学逻辑。

函数和过程都是子程序,但用途不同:

  • 函数是对表达式的抽象:就像数学运算符(Ada 中的运算符只是一个函数)。理想情况下,它提供来自多个操作数的结果而不是其他任何东西,使它们保持不变并且没有状态和副作用。这种理想被称为“纯函数”(并且应用“pragma pure”要求编译器检查其纯度)——类似的限制适用于函数式编程 (FP) 语言。纯函数允许进行大量优化(因为重新排序它们不会改变结果)。在实践中,Ada 并没有那么严格,也允许不纯函数。

  • 过程是对语句的抽象。它通常具有一些物理效果(例如改变状态),因为它不提供结果。

因此,表达式和语句之间的逻辑分离作为函数和过程之间的分离被延续到子程序(抽象)中。

这可能是决定使用哪个的最佳方式。

  • 或者,使过程返回访问类型(指针)并记住在完成后释放它。可行,不过那只是用Ada写一个C程序而已。 (2认同)

Jer*_*ere 5

Brian Drummond 已经直接回答了您的问题,但我想添加一些附加信息:如果您的类型具有某种初始化过程,则在 Ada2005/Ada2012 中,您可以使用扩展返回语法将其转换为初始化函数。它甚至适用于有限的类型。

假设您有一个类型如下的包:

package Example is

    type My_Type is limited private;

    procedure Initialize(Self : in out My_Type; Value : Integer);
    procedure Print(Self : My_Type);

private

    type My_Type is limited record
        Value : Integer := 0;
    end record;

end Example;

package body Example is
    procedure Initialize(Self : in out My_Type; Value : Integer) is
    begin
        Self.Value := Value;
    end Initialize;

    procedure Print(Self : My_Type) is
    begin
        Ada.Text_IO.Put_Line(Self.Value'Image);
    end Print;
end Example;
Run Code Online (Sandbox Code Playgroud)

然后,您可以从该过程中创建自己的初始化函数,执行如下操作:

function Make_My_Type (Value : Integer) return Example.My_Type is
begin
    return Result : Example.My_Type do
        Example.Initialize(Result,Value);
    end return;
end Make_My_Type;
Run Code Online (Sandbox Code Playgroud)

并且您可以使用隐藏在函数下方的过程轻松初始化变量:

procedure Test
   Thing : Example.My_Type := Make_My_Type(21);
begin
   Example.Print(Thing);
end Test;
Run Code Online (Sandbox Code Playgroud)

这与仅仅创建一个变量并返回它不同。您无法使用有限类型执行此操作,但使用扩展返回语法,您可以为任何类型执行此操作。

这里还有一些关于扩展返回语句的附加信息