首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何编写泛型实例化的规范?

如何编写泛型实例化的规范?
EN

Stack Overflow用户
提问于 2018-02-23 21:10:13
回答 4查看 606关注 0票数 1

我将从Ada中的一个通用过程的经典示例开始:

代码语言:javascript
复制
-------------------------
--  swaps.ads
-------------------------
package Swaps is
  generic
    type E is private;
  procedure Generic_Swap (Left, Right : in out E);
end Swaps;
代码语言:javascript
复制
-------------------------
--  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中的body声明中

代码语言:javascript
复制
procedure String_Swap is new Generic_Swap (String);

但是,如果我没有向swaps.ads中的规范添加任何内容,那么没有一个包可以使用这个过程。例如:

代码语言:javascript
复制
-------------------------
--  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;

我尝试将该过程的类型添加到规范中:

代码语言:javascript
复制
procedure String_Swap (Left, Right : in out String);

但是Ada抱怨这个规范缺少一个主体,并且swaps.adb中的定义与它冲突。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2018-02-24 10:54:32

您不能将泛型用于String类型,因为它是一个无约束类型。但是,让我们使用Ada.Strings.Unbounded.Unbounded_String代替。

你要做的是:

  1. 在包规范中发布适当过程的规范。
  2. 通过调用内部实例化的泛型过程来实现公共过程。
代码语言:javascript
复制
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;
代码语言:javascript
复制
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;

但总的来说,我更愿意将泛型的实例化与这些泛型的规范和实现完全分开。

票数 3
EN

Stack Overflow用户

发布于 2018-02-25 09:08:52

我解决这个问题的方法是使用一个子包:

代码语言:javascript
复制
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;

请注意,可以编写一个处理不确定类型的泛型:

代码语言:javascript
复制
generic
   type Element (<>) is private;

并将Generic_Swap的主体更改为

代码语言:javascript
复制
procedure Generic_Swap (Left, Right : in out Element) is
   Temp : constant Element := Left;
begin -- Generic_Swap
   Left := Right;
   Right := Temp;
end Generic_Swap;

但是要使用它,实际对象必须是无约束的,或者具有相同的子类型。

票数 4
EN

Stack Overflow用户

发布于 2018-02-23 22:39:44

Swaps的用户唯一能看到的就是规范。由于规范中没有关于String_Swap的任何内容,所以包主体中的任何篡改都不会产生任何影响。

如果您希望“实现用于交换字符串的专用String_Swap过程”,则必须将其包括在规范中:

代码语言:javascript
复制
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编译时,我们得到

代码语言:javascript
复制
 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的片段);因此,即使您的过程Main是在不使用泛型的情况下写出的,它在运行时也会失败,从而导致一个约束错误。看看Ada.Strings.Unbounded at ARM A.4.5

所以,尝试一种明确的类型:

代码语言:javascript
复制
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;

不幸的是,

代码语言:javascript
复制
 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;

解决方案必须是单独实例化:也许在库级别,

代码语言:javascript
复制
with Swaps;
procedure Character_Swap is new Swaps.Generic_Swap(Character);

让您的用户根据自己的意愿实例化泛型会容易得多。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48956257

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档