通用函数返回映射
Generic function returning map
在以下示例中,一个有序映射被创建并由函数返回:
with Ada.Containers.Ordered_Maps;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
procedure Main is
package My_Map is new Ada.Containers.Ordered_Maps
(Key_Type => Natural,
Element_Type => Unbounded_String);
function Create_Map return My_Map.Map is
Map_Instance : My_Map.Map;
begin
Map_Instance.Insert (1, To_Unbounded_String ("Foo"));
Map_Instance.Insert (2, To_Unbounded_String ("Bar"));
return Map_Instance;
end Create_Map;
begin
null;
end Main;
我想知道是否可以将函数 Create_Map
转换为更通用的函数?下面的代码展示了我的想法,但不幸的是我真的不知道正确的形式类型 ???
:
generic
type Key_Type is ???;
type Element_Type is ???;
type Map_Type is ???;
function Create_Map_Generic return Map_Type is
Map_Instance : Map_Type;
begin
-- Inserts calls would be based on parsing data ...
return Map_Instance;
end;
package My_Map_One is new Ada.Containers.Ordered_Maps
(Key_Type => Natural,
Element_Type => Unbounded_String);
function Create_Map_One is new Create_Map_Generic
(Key_Type => Natural,
Element_Type => Unbounded_String,
Map_Type => My_Map_One.Map);
package My_Map_Two is new Ada.Containers.Ordered_Maps
(Key_Type => Unbounded_String,
Element_Type => Positive);
function Create_Map_Two is new Create_Map_Generic
(Key_Type => Unbounded_String,
Element_Type => Positive,
Map_Type => My_Map_Two.Map);
正式类型 Key_Type
和 Element_Type
指定了两次(包声明和泛型函数的实例化)。这些可以从包本身的声明中提取吗?
我不确定这是否能回答您的用例,但这里是..
我不认为你可以只用一个通用函数来做到这一点;我认为最好是作为一个通用包(声明地图,从例如 Positive
到 Unbounded_String
)包含一个通用函数以使用特定的人口子程序创建地图。
外泛型:
with Ada.Containers.Ordered_Maps;
generic
type Key_Type is private;
type Element_Type is private;
with function "<" (Left, Right : Key_Type) return Boolean is <>;
with function "=" (Left, Right : Element_Type) return Boolean is <>;
package Maps_G is
package Maps is new Ada.Containers.Ordered_Maps
(Key_Type => Key_Type,
Element_Type => Element_Type,
"<" => "<",
"=" => "=");
subtype Map is Maps.Map;
generic
with procedure Populate (The_Map : in out Map);
function Create_Map return Map;
end Maps_G;
及其正文:
package body Maps_G is
function Create_Map return Map is
begin
return M : Map do
Populate (M);
end return;
end Create_Map;
end Maps_G;
加上一点测试程序:
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Maps_G;
with Ada.Text_IO;
procedure Test is
package P_To_UBS_Maps is new Maps_G (Key_Type => Positive,
Element_Type => Unbounded_String);
procedure Populate (The_Map : in out P_To_UBS_Maps.Map) is
begin
The_Map.Insert (42, To_Unbounded_String ("the answer"));
The_Map.Insert (1, To_Unbounded_String ("one"));
end Populate;
function Create
is new P_To_UBS_Maps.Create_Map (Populate);
M : P_To_UBS_Maps.Map := Create;
begin
for J in M.Iterate loop
Ada.Text_IO.Put_Line (P_To_UBS_Maps.Maps.Key (J)'Image
& " -> "
& To_String (P_To_UBS_Maps.Maps.Element (J)));
end loop;
end Test;
构建 & 运行:
$ gnatmake test -f -g
gcc -c -g test.adb
gcc -c -g maps_g.adb
gnatbind -x test.ali
gnatlink test.ali -g
gnatlink: warning: executable name "test" may conflict with shell command
$ ./test
1 -> one
42 -> the answer
完成了,与直接调用 Populate
相比似乎没有真正的优势。
西蒙给出了更好更完整的答案。我只是提供一个替代方案,将地图包作为形式参数传入。为此,您可以将包作为形式参数传递,只要它的参数也作为形式参数发送:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers.Ordered_Maps;
procedure Hello is
generic
type Key_Type is private;
type Element_Type is private;
with function "<"(L,R : Key_Type) return Boolean is <>;
with function "="(L,R : Key_Type) return Boolean is <>;
with package Map_Package is new Ada.Containers.Ordered_Maps
(Key_Type => Key_Type,
Element_Type => Element_Type,
"<" => "<",
"=" => "=");
function Create_Map_Generic return Map_Package.Map;
function Create_Map_Generic return Map_Package.Map is
begin
return Result : Map_Package.Map do
null; -- replace with your input based creation
end return;
end Create_Map_Generic;
-- Just a nonsense type to test out compilation
type My_Key is null record;
function "<"(L,R : My_Key) return Boolean is (True);
function "="(L,R : My_Key) return Boolean is (True);
package Maps is new Ada.Containers.Ordered_Maps
(Key_Type => My_Key,
Element_Type => Integer);
function Create is new Create_Map_Generic
(Key_Type => My_Key,
Element_Type => Integer,
Map_Package => Maps);
begin
Put_Line("Hello, world!");
end Hello;
作为额外的花絮,如果您不关心函数内部的键和元素类型是什么(我想您关心,但以防万一),那么您不必指定它们,只需简单地做:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers.Ordered_Maps;
procedure Hello is
generic
with package Map_Package is new Ada.Containers.Ordered_Maps
(others => <>);
function Create_Map_Generic return Map_Package.Map;
function Create_Map_Generic return Map_Package.Map is
begin
return Result : Map_Package.Map do
null; -- replace with your input based creation
end return;
end Create_Map_Generic;
-- Just a nonsense type to test out compilation
type My_Key is null record;
function "<"(L,R : My_Key) return Boolean is (True);
function "="(L,R : My_Key) return Boolean is (True);
package Maps is new Ada.Containers.Ordered_Maps
(Key_Type => My_Key,
Element_Type => Integer);
function Create is new Create_Map_Generic
(Map_Package => Maps);
begin
Put_Line("Hello, world!");
end Hello;
你也可以在中间折衷,这取决于你想在你的创建函数中使用什么:
generic
type Key_Type is private;
type Element_Type is private;
with package Map_Package is new Ada.Containers.Ordered_Maps
(Key_Type => Key_Type,
Element_Type => Element_Type,
others => <>);
function Create_Map_Generic return Map_Package.Map;
在以下示例中,一个有序映射被创建并由函数返回:
with Ada.Containers.Ordered_Maps;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
procedure Main is
package My_Map is new Ada.Containers.Ordered_Maps
(Key_Type => Natural,
Element_Type => Unbounded_String);
function Create_Map return My_Map.Map is
Map_Instance : My_Map.Map;
begin
Map_Instance.Insert (1, To_Unbounded_String ("Foo"));
Map_Instance.Insert (2, To_Unbounded_String ("Bar"));
return Map_Instance;
end Create_Map;
begin
null;
end Main;
我想知道是否可以将函数 Create_Map
转换为更通用的函数?下面的代码展示了我的想法,但不幸的是我真的不知道正确的形式类型 ???
:
generic
type Key_Type is ???;
type Element_Type is ???;
type Map_Type is ???;
function Create_Map_Generic return Map_Type is
Map_Instance : Map_Type;
begin
-- Inserts calls would be based on parsing data ...
return Map_Instance;
end;
package My_Map_One is new Ada.Containers.Ordered_Maps
(Key_Type => Natural,
Element_Type => Unbounded_String);
function Create_Map_One is new Create_Map_Generic
(Key_Type => Natural,
Element_Type => Unbounded_String,
Map_Type => My_Map_One.Map);
package My_Map_Two is new Ada.Containers.Ordered_Maps
(Key_Type => Unbounded_String,
Element_Type => Positive);
function Create_Map_Two is new Create_Map_Generic
(Key_Type => Unbounded_String,
Element_Type => Positive,
Map_Type => My_Map_Two.Map);
正式类型 Key_Type
和 Element_Type
指定了两次(包声明和泛型函数的实例化)。这些可以从包本身的声明中提取吗?
我不确定这是否能回答您的用例,但这里是..
我不认为你可以只用一个通用函数来做到这一点;我认为最好是作为一个通用包(声明地图,从例如 Positive
到 Unbounded_String
)包含一个通用函数以使用特定的人口子程序创建地图。
外泛型:
with Ada.Containers.Ordered_Maps;
generic
type Key_Type is private;
type Element_Type is private;
with function "<" (Left, Right : Key_Type) return Boolean is <>;
with function "=" (Left, Right : Element_Type) return Boolean is <>;
package Maps_G is
package Maps is new Ada.Containers.Ordered_Maps
(Key_Type => Key_Type,
Element_Type => Element_Type,
"<" => "<",
"=" => "=");
subtype Map is Maps.Map;
generic
with procedure Populate (The_Map : in out Map);
function Create_Map return Map;
end Maps_G;
及其正文:
package body Maps_G is
function Create_Map return Map is
begin
return M : Map do
Populate (M);
end return;
end Create_Map;
end Maps_G;
加上一点测试程序:
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Maps_G;
with Ada.Text_IO;
procedure Test is
package P_To_UBS_Maps is new Maps_G (Key_Type => Positive,
Element_Type => Unbounded_String);
procedure Populate (The_Map : in out P_To_UBS_Maps.Map) is
begin
The_Map.Insert (42, To_Unbounded_String ("the answer"));
The_Map.Insert (1, To_Unbounded_String ("one"));
end Populate;
function Create
is new P_To_UBS_Maps.Create_Map (Populate);
M : P_To_UBS_Maps.Map := Create;
begin
for J in M.Iterate loop
Ada.Text_IO.Put_Line (P_To_UBS_Maps.Maps.Key (J)'Image
& " -> "
& To_String (P_To_UBS_Maps.Maps.Element (J)));
end loop;
end Test;
构建 & 运行:
$ gnatmake test -f -g
gcc -c -g test.adb
gcc -c -g maps_g.adb
gnatbind -x test.ali
gnatlink test.ali -g
gnatlink: warning: executable name "test" may conflict with shell command
$ ./test
1 -> one
42 -> the answer
完成了,与直接调用 Populate
相比似乎没有真正的优势。
西蒙给出了更好更完整的答案。我只是提供一个替代方案,将地图包作为形式参数传入。为此,您可以将包作为形式参数传递,只要它的参数也作为形式参数发送:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers.Ordered_Maps;
procedure Hello is
generic
type Key_Type is private;
type Element_Type is private;
with function "<"(L,R : Key_Type) return Boolean is <>;
with function "="(L,R : Key_Type) return Boolean is <>;
with package Map_Package is new Ada.Containers.Ordered_Maps
(Key_Type => Key_Type,
Element_Type => Element_Type,
"<" => "<",
"=" => "=");
function Create_Map_Generic return Map_Package.Map;
function Create_Map_Generic return Map_Package.Map is
begin
return Result : Map_Package.Map do
null; -- replace with your input based creation
end return;
end Create_Map_Generic;
-- Just a nonsense type to test out compilation
type My_Key is null record;
function "<"(L,R : My_Key) return Boolean is (True);
function "="(L,R : My_Key) return Boolean is (True);
package Maps is new Ada.Containers.Ordered_Maps
(Key_Type => My_Key,
Element_Type => Integer);
function Create is new Create_Map_Generic
(Key_Type => My_Key,
Element_Type => Integer,
Map_Package => Maps);
begin
Put_Line("Hello, world!");
end Hello;
作为额外的花絮,如果您不关心函数内部的键和元素类型是什么(我想您关心,但以防万一),那么您不必指定它们,只需简单地做:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers.Ordered_Maps;
procedure Hello is
generic
with package Map_Package is new Ada.Containers.Ordered_Maps
(others => <>);
function Create_Map_Generic return Map_Package.Map;
function Create_Map_Generic return Map_Package.Map is
begin
return Result : Map_Package.Map do
null; -- replace with your input based creation
end return;
end Create_Map_Generic;
-- Just a nonsense type to test out compilation
type My_Key is null record;
function "<"(L,R : My_Key) return Boolean is (True);
function "="(L,R : My_Key) return Boolean is (True);
package Maps is new Ada.Containers.Ordered_Maps
(Key_Type => My_Key,
Element_Type => Integer);
function Create is new Create_Map_Generic
(Map_Package => Maps);
begin
Put_Line("Hello, world!");
end Hello;
你也可以在中间折衷,这取决于你想在你的创建函数中使用什么:
generic
type Key_Type is private;
type Element_Type is private;
with package Map_Package is new Ada.Containers.Ordered_Maps
(Key_Type => Key_Type,
Element_Type => Element_Type,
others => <>);
function Create_Map_Generic return Map_Package.Map;