You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何创建可接收A_Type/B_Type的通用Ada公共库(不依赖A/B包)

解决方案

在Ada中,要实现不依赖具体类型包(A、B)的通用库,同时支持接收不同类型参数,最适合的方式是利用抽象Tagged类型(Ada的面向对象机制),具体步骤如下:

1. 定义通用库CommonLib

在CommonLib中声明一个抽象Tagged类型作为通用参数的基类,同时定义操作该类型的过程。这样CommonLib无需引入A或B包:

package CommonLib is
   -- 定义抽象Tagged类型,作为所有可传入DoStuff的类型的基类
   type Generic_Type is abstract tagged null record;

   -- 接收抽象类型的Classwide类型(支持所有派生自Generic_Type的具体类型)
   procedure DoStuff (Param : Generic_Type'Class);
end CommonLib;

如果DoStuff需要访问具体类型的内部字段,还需要在抽象类型中定义抽象操作,让具体类型去实现:

package CommonLib is
   type Generic_Type is abstract tagged null record;
   -- 定义抽象操作,由具体类型实现字段访问逻辑
   function Get_Access (Self : Generic_Type) return access constant String is abstract;

   procedure DoStuff (Param : Generic_Type'Class);
end CommonLib;

package body CommonLib is
   procedure DoStuff (Param : Generic_Type'Class) is
      Access_Val : access constant String := Param.Get_Access;
   begin
      -- 这里可以使用抽象操作获取的内容进行通用处理
      null;
   end DoStuff;
end CommonLib;

2. 修改A、B包的类型定义

让A_Type和B_Type派生自CommonLib中的抽象Tagged类型,这样它们就可以被CommonLib的DoStuff接收。此时A、B包需要引入CommonLib,但CommonLib依然不需要引入A、B:

package A is
   use CommonLib;
   type A is tagged null record; -- 原A包的类型,保持不变
   type Field_Type is ...; -- 补充Field_Type的定义

   -- 让A_Type派生自Generic_Type
   type A_Type is new Generic_Type with record
      Field : Field_Type;
      A_Access : access A;
   end record;

   -- 如果需要实现抽象操作(比如上面的Get_Access)
   overriding function Get_Access (Self : A_Type) return access constant String is
   begin
      -- 返回A_Type中A_Access的相关内容,根据实际需求实现
      return null;
   end Get_Access;
end A;
package B is
   use CommonLib;
   type B is tagged null record; -- 原B包的类型,保持不变
   type OtherField_Type is ...; -- 补充OtherField_Type的定义

   -- 让B_Type派生自Generic_Type
   type B_Type is new Generic_Type with record
      OtherField : OtherField_Type;
      B_Access : access B;
   end record;

   -- 实现抽象操作
   overriding function Get_Access (Self : B_Type) return access constant String is
   begin
      return null;
   end Get_Access;
end B;

3. 调用方式

此时就可以按照你期望的方式直接调用CommonLib的DoStuff:

with CommonLib; use CommonLib;
with A; use A;
with B; use B;

procedure Main is
   My_A : A_Type;
   My_B : B_Type;
begin
   CommonLib.DoStuff(My_A);
   CommonLib.DoStuff(My_B);
end Main;

替代方案:泛型包

如果不需要面向对象的分发逻辑,也可以使用泛型包实现。CommonLib定义为泛型包,由调用方传入具体类型进行实例化:

package CommonLib is
   generic
      type T is private;
   package Generic_Operations is
      procedure DoStuff (Param : T);
   end Generic_Operations;
end CommonLib;

package body CommonLib is
   package body Generic_Operations is
      procedure DoStuff (Param : T) is
      begin
         -- 通用处理逻辑
         null;
      end DoStuff;
   end Generic_Operations;
end CommonLib;

调用时需要先实例化泛型包:

with CommonLib; use CommonLib;
with A; use A;

package A_Operations is new Generic_Operations (T => A_Type);

procedure Main is
   My_A : A_Type;
begin
   A_Operations.DoStuff(My_A);
end Main;

这种方式的缺点是需要为每个类型单独实例化包,不如抽象Tagged类型的调用方式简洁,但如果DoStuff的逻辑完全不依赖类型内部结构,这种方式也适用。

内容的提问来源于stack exchange,提问作者A.Pissicat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 15:05:29