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



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

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

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

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

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

两个让你开始...

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

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

此示例显示了通过调用Read_File函数初始化的变量 "text",以在循环的每次迭代中保存不同文件的内容。安全,无需"malloc"或"免费"或指针。(在本例中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;

编辑:我想我最好提到基本的数学原理,因为Ada比许多其他语言更紧密地基于数理逻辑。

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

  • 函数是对表达式的抽象:就像数学运算符一样(Ada中的运算符只是一个函数(。理想情况下,它提供许多操作数的结果,而不是其他任何操作数,使它们保持不变,没有状态,也没有副作用。这种理想被称为"纯函数"(应用"纯编译指示"要求编译器检查其纯度( - 类似的限制适用于函数式编程(FP(语言。纯函数允许一大堆优化(因为重新排序它们不会改变结果(。实际上,Ada 并没有那么严格,也允许不纯的功能。

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

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

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

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;

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

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;

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

procedure Test
Thing : Example.My_Type := Make_My_Type(21);
begin
Example.Print(Thing);
end Test;

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

以下是有关扩展返回语句的一些附加信息。

最新更新