Ada 是否有关于何时使用函数与带输出参数的过程的惯用规则?
Does Ada have any idiomatic rules on when to use a function versus a procedure with an output parameter?
您可以通过函数 return 为变量赋值:
My_Int : Integer := My_Math_Func [(optional params)];
或者你可以像这样用一个过程来做(假设 My_Int
已经声明):
My_Math_Proc ([optional params;] [in] out My_Int);
显然,过程不能像第一个示例中的函数那样初始化变量,但我希望有一些具体、实用的规则来说明何时以及为何选择一个而不是另一个。
两个让你入门...
当要 return 编辑多个结果时,具有多个 OUT 参数的过程通常是一个不错的选择。
如果对象的大小在子程序调用之前未知,则不能使用 OUT 参数,因为它必须精确地声明为正确的大小,但是函数 return 可以通过以下方式设置大小在调用者中初始化变量。这通常与在 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;
编辑:我想我最好提一下基本的数学原理,因为与许多其他语言相比,Ada 更紧密地基于数学逻辑。
函数和过程都是子程序,只是用途不同:
函数是对表达式的抽象:就像数学运算符(Ada 中的运算符只是一个函数)。理想情况下,它提供来自多个操作数的结果 而没有其他任何东西 ,保持它们不变并且没有状态和副作用。这种理想称为 "pure function"(应用 "pragma pure" 要求编译器检查其纯度)——类似的限制适用于函数式编程 (FP) 语言。纯函数允许进行大量优化(因为对它们重新排序不会改变结果)。实际上 Ada 并没有那么严格,也允许不纯函数。
过程是对语句的抽象。它通常具有一些物理效果(例如改变状态),因为它不提供结果。
因此,表达式和语句之间的逻辑分离被转移到子程序(抽象)中,作为函数和过程之间的分离。
这可能是决定使用哪个的最佳方式。
Brian Drummond 已经直接回答了你的问题,但我想添加一些额外的信息:如果你的类型有某种初始化过程,在 Ada2005/Ada2012 中你可以使用 [=13 将其转换为初始化函数=].它甚至适用于有限的类型。
假设您有一个类型如下的包裹:
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;
这不同于仅仅创建一个变量并返回它。您无法对有限类型执行此操作,但使用 extended return syntax,您可以对任何类型执行此操作。
您可以通过函数 return 为变量赋值:
My_Int : Integer := My_Math_Func [(optional params)];
或者你可以像这样用一个过程来做(假设 My_Int
已经声明):
My_Math_Proc ([optional params;] [in] out My_Int);
显然,过程不能像第一个示例中的函数那样初始化变量,但我希望有一些具体、实用的规则来说明何时以及为何选择一个而不是另一个。
两个让你入门...
当要 return 编辑多个结果时,具有多个 OUT 参数的过程通常是一个不错的选择。
如果对象的大小在子程序调用之前未知,则不能使用 OUT 参数,因为它必须精确地声明为正确的大小,但是函数 return 可以通过以下方式设置大小在调用者中初始化变量。这通常与在 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;
编辑:我想我最好提一下基本的数学原理,因为与许多其他语言相比,Ada 更紧密地基于数学逻辑。
函数和过程都是子程序,只是用途不同:
函数是对表达式的抽象:就像数学运算符(Ada 中的运算符只是一个函数)。理想情况下,它提供来自多个操作数的结果 而没有其他任何东西 ,保持它们不变并且没有状态和副作用。这种理想称为 "pure function"(应用 "pragma pure" 要求编译器检查其纯度)——类似的限制适用于函数式编程 (FP) 语言。纯函数允许进行大量优化(因为对它们重新排序不会改变结果)。实际上 Ada 并没有那么严格,也允许不纯函数。
过程是对语句的抽象。它通常具有一些物理效果(例如改变状态),因为它不提供结果。
因此,表达式和语句之间的逻辑分离被转移到子程序(抽象)中,作为函数和过程之间的分离。
这可能是决定使用哪个的最佳方式。
Brian Drummond 已经直接回答了你的问题,但我想添加一些额外的信息:如果你的类型有某种初始化过程,在 Ada2005/Ada2012 中你可以使用 [=13 将其转换为初始化函数=].它甚至适用于有限的类型。
假设您有一个类型如下的包裹:
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;
这不同于仅仅创建一个变量并返回它。您无法对有限类型执行此操作,但使用 extended return syntax,您可以对任何类型执行此操作。