我将从Ada中通用程序的经典示例开始:
-------------------------
-- swaps.ads
-------------------------
package Swaps is
generic
type E is private;
procedure Generic_Swap (Left, Right : in out E);
end Swaps;
-------------------------
-- swaps.adb
-------------------------
package body Swaps is
procedure Generic_Swap (Left, Right : in out E) is
Temporary : E;
begin
Temporary := Left;
Left := Right;
Right := Temporary;
end Generic_Swap;
end Swaps;
现在假设我想实现一个专门用于交换字符串的String_Swap
过程,并将其提供给我的包的所有用户。我可以将以下内容添加到swaps.adb
中的正文声明中:
procedure String_Swap is new Generic_Swap (String);
但是,如果我在swaps.ads
中没有添加任何规范,那么没有包可以使用此过程。例如:
-------------------------
-- main.adb
-------------------------
with Swaps; use Swaps;
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
First : String := "world!";
Second : String := "Hello, ";
begin
String_Swap (First, Second); -- #Error: String_Swap is undefined#
Put_Line (First);
Put_Line (Second);
end Main;
我试图将程序类型添加到规范中:
procedure String_Swap (Left, Right : in out String);
然后Ada抱怨说这个规范缺少一个主体,swaps.adb
中的定义与它相冲突。
答案 0 :(得分:4)
我要解决这个问题的方法是使用子包:
with Ada.Strings.Unbounded;
package Swaps.Instances is
procedure Swap is new Generic_Swap (Element => Character);
procedure Swap is new Generic_Swap (Element => Ada.Strings.Unbounded.Unbounded_String;
...
end Swaps.Instances;
请注意,可以编写一个处理不定类型的泛型:
generic
type Element (<>) is private;
并将Generic_Swap
的正文更改为
procedure Generic_Swap (Left, Right : in out Element) is
Temp : constant Element := Left;
begin -- Generic_Swap
Left := Right;
Right := Temp;
end Generic_Swap;
但要使用它,实际对象必须是不受约束的或具有相同的子类型。
答案 1 :(得分:3)
Swaps
的用户唯一可以看到的是规范。由于规范中没有String_Swap
,因此包 body 中的任何数量都不会产生任何差异。
如果你想实现一个专门用于交换字符串&#34;的String_Swap
程序,你必须将它包含在规范中:
package Swaps is
generic
type E is private;
procedure Generic_Swap(Left, Right : in out E);
procedure String_Swap is new Generic_Swap(String);
end Swaps;
这是一个不好的例子:当用-gnatl
编译时,我们得到
1. package Swaps is
2. generic
3. type E is private;
4. procedure Generic_Swap(Left, Right : in out E);
5. procedure String_Swap is new Generic_Swap(String);
|
>>> actual for "E" must be a definite subtype
6. end Swaps;
这是因为String
类型是不确定的,即特定String
具有特定长度,并且只能分配给另一个String
(或String
的切片1}})长度相同;因此,即使您的过程Main
未使用泛型写出,它也会在运行时因约束错误而失败。在ARM A.4.5点击Ada.Strings.Unbounded
。
所以,尝试一下确定的类型:
package Swaps is
generic
type E is private;
procedure Generic_Swap(Left, Right : in out E);
procedure Character_Swap is new Generic_Swap(Character);
end Swaps;
不幸的是,
1. package Swaps is
2. generic
3. type E is private;
4. procedure Generic_Swap(Left, Right : in out E);
5. procedure Character_Swap is new Generic_Swap(Character);
|
>>> warning: cannot instantiate "Generic_Swap" before body seen
>>> warning: Program_Error will be raised at run time
6. end Swaps;
解决方案必须单独实例化:可能在库级别,
with Swaps;
procedure Character_Swap is new Swaps.Generic_Swap(Character);
让用户根据自己的意愿实例化通用设置会更容易。
答案 2 :(得分:3)
您不能将您的通用用于类型String
,因为它是一种不受约束的类型。但是让我们改用Ada.Strings.Unbounded.Unbounded_String
。
你要做的是:
with Ada.Strings.Unbounded;
package Swaps is
generic
type Element_Type is private;
procedure Generic_Swap (Left, Right : in out Element_Type);
procedure Swap (Left, Right : in out Ada.Strings.Unbounded.Unbounded_String);
end Swaps;
package body Swaps is
procedure Generic_Swap (Left, Right : in out Element_Type) is
Temporary : Element_Type;
begin
Temporary := Left;
Left := Right;
Right := Temporary;
end Generic_Swap;
procedure Swap_Unbounded_Strings is
new Generic_Swap (Element_Type => Ada.Strings.Unbounded.Unbounded_String);
procedure Swap (Left, Right : in out Ada.Strings.Unbounded.Unbounded_String) is
begin
Swap_Unbounded_Strings (Left => Left,
Right => Right);
end Swap;
end Swaps;
但总的来说,我更喜欢将泛型的实例化与这些泛型的规范和实现完全分开。