能否声明同时适配受限数组与非受限数组的泛型函数?
Ada泛型数组查找函数适配受限与非受限数组的解决方案
问题背景
现有一个用于查找数组元素索引的Ada泛型函数,定义如下:
generic type T is private; type T_index is (<>); type T_array is array(T_index range <>) of T; function FindIndexGeneric(array: T_array; element: T; elementFound: out Boolean) return T_index;
该函数实例化为非受限数组(如String)时可正常运行:
function FindIndexString is new FindIndexGeneric (T=>Character, T_index=>Positive, T_array=>String);
但实例化为固定长度的受限数组时会报错:
type userIDIndex is Integer range 1..6; type userID is array(userIDIndex) of Character; function FindIndexUserID is new FindIndexGeneric (T=>Character, T_index=>userIDIndex, T_array=>userID); -- 错误提示:expect unconstrained array in instantiation of "T_array"
若将泛型中的数组声明改为type T_array is array(T_index) of T;,则可适配受限数组,但无法再实例化非受限数组。由于核心查找逻辑一致,无需编写多个泛型版本,需找到同时支持两种数组类型的方案。
解决方案
方案1:基于抽象数组操作的泛型定义
通过将数组类型声明为私有类型,并添加获取元素、索引范围的泛型回调函数,实现对任意数组类型(受限/非受限)的适配。
泛型函数定义
generic type T is private; type T_Index is (<>); type T_Array is private; -- 获取数组指定索引的元素 with function Element(Arr : T_Array; Idx : T_Index) return T; -- 获取数组的起始索引 with function First(Arr : T_Array) return T_Index; -- 获取数组的结束索引 with function Last(Arr : T_Array) return T_Index; function FindIndexGeneric(Arr : T_Array; Target : T; Found : out Boolean) return T_Index;
泛型函数实现
function FindIndexGeneric(Arr : T_Array; Target : T; Found : out Boolean) return T_Index is begin Found := False; for Idx in First(Arr)..Last(Arr) loop if Element(Arr, Idx) = Target then Found := True; return Idx; end if; end loop; -- 未找到时返回起始索引,可根据需求调整(如抛出异常) return First(Arr); end FindIndexGeneric;
实例化示例
- 非受限数组
String实例化:
function FindIndexString is new FindIndexGeneric (T => Character, T_Index => Positive, T_Array => String, Element => String.Element, First => String'First, Last => String'Last);
- 受限数组
userID实例化(Ada 2012及以上可用表达式函数简化):
type userIDIndex is Integer range 1..6; type userID is array(userIDIndex) of Character; function FindIndexUserID is new FindIndexGeneric (T => Character, T_Index => userIDIndex, T_Array => userID, Element => (function (Arr : userID; Idx : userIDIndex) return Character is (Arr(Idx))), First => (function (Arr : userID) return userIDIndex is (Arr'First)), Last => (function (Arr : userID) return userIDIndex is (Arr'Last)));
方案2:利用非受限数组基类型适配受限数组
对于受限数组,可直接以其对应的非受限数组基类型作为泛型的T_array参数,受限数组作为子类型可隐式转换为非受限数组类型,无需修改原泛型函数定义。
实例化示例
type userIDIndex is Integer range 1..6; type userID is array(userIDIndex) of Character; -- 以非受限数组基类型作为T_array参数 function FindIndexUserID is new FindIndexGeneric (T => Character, T_Index => userIDIndex, T_Array => array(userIDIndex range <>) of Character); -- 调用时可直接传入userID类型变量 declare ID : userID := "123456"; Found : Boolean; Idx : userIDIndex; begin Idx := FindIndexUserID(ID, '3', Found); end;
总结
方案1通过抽象数组操作实现了最大的灵活性,可适配任意自定义数组类型;方案2无需修改原泛型函数,仅需调整实例化时的数组类型参数,实现成本更低,适合已有泛型函数的场景。
内容的提问来源于stack exchange,提问作者Adi
相关产品推荐
相关产品推荐

