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

Ada中下标/子程序调用运算符的重载方法

关于Ada.Containers.Vectors下标访问的实现与自定义复刻

我们都熟知且常用Ada.Containers.Vectors,以下是其使用示例:

with Ada.Text_IO;
with Ada.Containers.Vectors;

procedure Example is
   use Ada.Text_IO;

   package Vectors_Integer is new Ada.Containers.Vectors (Natural, Integer);
   use Vectors_Integer;

   My_Vec : Vector := 1 & 2 & 3;
begin
   Put_Line (Integer'Image (My_Vec (0)));
end Example;

我的问题很明确:My_Vec(0)是如何实现的?如何在自定义类型中复刻这一行为?

我已在网上搜索许久,但未找到该表达式的实现说明。下标运算符与函数调用运算符语法相同,无法通过常规运算符重载语法实现重载。我查阅了Ada.Containers.Vectors的包规范,未发现Vector类型显式重载该运算符的相关定义。我曾猜测Element函数与此相关,但无法借助它定义出复刻Vector行为的自定义类型。我完全不清楚如何重载下标运算符,尽管显然这是可行的。


一、My_Vec(0)的实现原理

Ada中并没有所谓的“下标运算符重载”语法,My_Vec(0)这种下标访问是编译器内置的语法糖,它会自动映射到容器包中预定义的两个子程序:

  • 读取值时(如My_Vec(0)),编译器将其转换为调用Element(My_Vec, 0),该函数在Ada.Containers.Vectors包规范中的签名为:
    function Element (Container : Vector; Index : Index_Type) return Element_Type;
    
  • 赋值时(如My_Vec(0) := 5),编译器转换为调用Replace_Element过程,签名为:
    procedure Replace_Element (Container : in out Vector; Index : Index_Type; New_Item : Element_Type);
    

你在包规范中看不到显式的运算符重载,是因为这种映射是Ada语言规则原生支持的——只要容器类型所在包中定义了符合上述签名的Element和Replace_Element,编译器就会自动识别并启用下标访问语法。

二、在自定义类型中复刻该行为

要让自定义类型支持下标访问,只需遵循以下步骤:

  1. 定义自定义容器类型(可以是私类型或普通类型)
  2. 定义符合签名要求的Element函数(用于读取操作)
  3. 定义符合签名要求的Replace_Element过程(用于写入操作,只读场景可省略)

以下是一个简单的示例,实现类似Vector的动态整数容器并支持下标访问:

with Ada.Text_IO; use Ada.Text_IO;

package Custom_Vectors is
   type Vector is private;

   -- 辅助操作:初始化空容器、添加元素
   function Empty_Vector return Vector;
   function "&" (Left : Vector; Right : Integer) return Vector;

   -- 必须定义:支持下标读取的Element函数
   function Element (Container : Vector; Index : Natural) return Integer;
   -- 可选定义:支持下标的Replace_Element过程
   procedure Replace_Element (Container : in out Vector; Index : Natural; New_Item : Integer);

private
   -- 内部用数组模拟动态存储(实际项目可按需优化为动态分配)
   type Integer_Array is array (Natural range <>) of Integer;
   type Vector is record
      Data : Integer_Array (0 .. 9);
      Last : Natural := -1;
   end record;
end Custom_Vectors;

package body Custom_Vectors is
   function Empty_Vector return Vector is
   begin
      return (Data => (others => 0), Last => -1);
   end Empty_Vector;

   function "&" (Left : Vector; Right : Integer) return Vector is
      Result : Vector := Left;
   begin
      if Result.Last < Result.Data'Last then
         Result.Last := Result.Last + 1;
         Result.Data(Result.Last) := Right;
      end if;
      return Result;
   end "&";

   function Element (Container : Vector; Index : Natural) return Integer is
   begin
      if Index > Container.Last then
         raise Constraint_Error with "Index out of bounds";
      end if;
      return Container.Data(Index);
   end Element;

   procedure Replace_Element (Container : in out Vector; Index : Natural; New_Item : Integer) is
   begin
      if Index > Container.Last then
         raise Constraint_Error with "Index out of bounds";
      end if;
      Container.Data(Index) := New_Item;
   end Replace_Element;
end Custom_Vectors;

-- 测试自定义容器
procedure Test_Custom_Vector is
   use Custom_Vectors;
   My_Vec : Vector := Empty_Vector & 1 & 2 & 3;
begin
   -- 下标读取,编译器自动转为Element(My_Vec, 0)
   Put_Line(Integer'Image(My_Vec(0)));
   -- 下标写入,编译器自动转为Replace_Element(My_Vec, 1, 5)
   My_Vec(1) := 5;
   Put_Line(Integer'Image(My_Vec(1)));
end Test_Custom_Vector;

关键注意点

  • Element和Replace_Element的参数签名必须严格匹配:第一个参数为容器类型,第二个为索引类型,Element返回元素类型,Replace_Element第三个参数为元素类型。
  • 索引类型可以是任意离散类型(如Natural、自定义枚举类型),只需保证与函数/过程的索引参数类型一致。
  • 只读场景仅需定义Element函数,读写场景需同时定义两个子程序。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 17:42:48