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

Ada语言中扩展带标记私有类型:链表实例定制与封装问题

嘿,我懂你想实现的需求——给Ada标准库的双向链表套一层自定义封装,既要加个打印链表的功能,又得把原容器里不需要的函数/过程藏起来,而且你还打算自己定义新的List和Cursor类型对吧?这在Ada里是非常典型的封装场景,我给你拆解下实现思路和具体代码:

核心思路:用组合代替继承

Ada的Ada.Containers.Doubly_Linked_Lists是带标记的类型,但直接继承它会把原容器的所有接口都暴露出来,不符合你隐藏部分功能的需求。更合理的方式是用组合:在自定义的List类型内部包含原链表的实例,自己定义Cursor类型包装原Cursor,只对外暴露你需要的接口。

具体实现步骤与代码示例

1. 定义泛型封装包

因为原链表是泛型的,你的封装包也得是泛型的。我们需要指定元素类型,再加一个打印单个元素的回调过程(毕竟泛型包不知道怎么打印自定义元素):

generic
   type Element_Type is private;
   -- 让用户提供打印单个元素的逻辑,可选默认值(如果元素是标准类型)
   with procedure Print_Element (Element : Element_Type) is <>;
package My_Wrapped_Lists is
   type List is tagged private;
   pragma Preelaborable_Initialization (List);

   type Cursor is private;
   pragma Preelaborable_Initialization (Cursor);

   -- 只暴露你需要的核心操作,比如添加、遍历、获取长度等
   procedure Append (Container : in out List; New_Item : Element_Type);
   function Length (Container : List) return Ada.Containers.Count_Type;
   function First (Container : List) return Cursor;
   function Next (Position : Cursor) return Cursor;
   function Element (Position : Cursor) return Element_Type;
   function Has_Element (Position : Cursor) return Boolean;

   -- 自定义的打印链表过程
   procedure Print_List (Container : List);

private
   -- 内部引用标准库的双向链表
   use Ada.Containers.Doubly_Linked_Lists;
   package Base_Lists is new Ada.Containers.Doubly_Linked_Lists (Element_Type);

   -- 自定义List包装原链表实例
   type List is tagged record
      Internal_List : Base_Lists.List;
   end record;

   -- 自定义Cursor包装原Cursor
   type Cursor is record
      Internal_Cursor : Base_Lists.Cursor;
   end record;

end My_Wrapped_Lists;

2. 实现包体

在包体里,我们把自定义接口的逻辑委托给内部的原链表,同时实现打印功能:

package body My_Wrapped_Lists is

   procedure Append (Container : in out List; New_Item : Element_Type) is
   begin
      Base_Lists.Append (Container.Internal_List, New_Item);
   end Append;

   function Length (Container : List) return Ada.Containers.Count_Type is
   begin
      return Base_Lists.Length (Container.Internal_List);
   end Length;

   function First (Container : List) return Cursor is
   begin
      return (Internal_Cursor => Base_Lists.First (Container.Internal_List));
   end First;

   function Next (Position : Cursor) return Cursor is
   begin
      return (Internal_Cursor => Base_Lists.Next (Position.Internal_Cursor));
   end Next;

   function Element (Position : Cursor) return Element_Type is
   begin
      return Base_Lists.Element (Position.Internal_Cursor);
   end Element;

   function Has_Element (Position : Cursor) return Boolean is
   begin
      return Base_Lists.Has_Element (Position.Internal_Cursor);
   end Has_Element;

   -- 遍历链表逐个打印元素
   procedure Print_List (Container : List) is
      Pos : Cursor := First (Container);
   begin
      while Has_Element (Pos) loop
         Print_Element (Element (Pos));
         Pos := Next (Pos);
      end loop;
   end Print_List;

end My_Wrapped_Lists;

3. 使用示例

比如你要封装一个Integer类型的链表,实例化时可以直接用默认的打印逻辑(如果元素是标准类型),或者自定义打印:

with My_Wrapped_Lists;
with Ada.Text_IO; use Ada.Text_IO;

procedure Test_List is
   -- 自定义Integer打印逻辑
   procedure Print_Int (X : Integer) is
   begin
      Put_Line ("Element: " & Integer'Image (X));
   end Print_Int;

   package Int_Lists is new My_Wrapped_Lists (Integer, Print_Int);
   use Int_Lists;

   My_List : List;
begin
   Append (My_List, 10);
   Append (My_List, 20);
   Append (My_List, 30);

   Put_Line ("List length: " & Count_Type'Image (Length (My_List)));
   Put_Line ("List elements:");
   Print_List (My_List);
end Test_List;
更优实现的小建议
  • 灵活的打印逻辑:泛型里的Print_Element用了is <>,意味着如果元素类型有默认的打印方式(比如String可以直接用Put_Line),用户可以不用显式提供这个过程,简化实例化。
  • 按需扩展接口:如果之后需要添加删除、插入等功能,只需要在包的可见部分添加对应的过程/函数,内部委托给原链表即可,完全控制暴露的范围。
  • Cursor安全性:自己封装Cursor可以避免用户直接操作原链表的Cursor,防止意外破坏内部状态,也能统一接口风格。

内容的提问来源于stack exchange,提问作者iconoclast2000

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:20:36