Ada:创建一种通用实例化(例如 Vectors)
Ada: Create a type of a generic instantiation (e.g. Vectors)
我正在尝试创建一个类型 'Path',它是一个点向量:
with Ada.Containers.Vectors;
use Ada.Containers;
package Geometry is
type Point is record
North : Integer := 0; -- millimetres
East : Integer := 0;
end record;
function Same_Point (A, B : Point) return Boolean is
(A.North = B.North and then A.East = B.East);
package Path_Points is new Vectors
(Element_Type => Point,
Index_Type => Positive,
"=" => Same_Point);
use Path_Points;
-- works, but poor readability. 'result' is a 'path', not a vector
Result : Vector;
-- What I'd like to do, a type called 'Path':
type Path is new Path_Points.Vector; -- WRONG
end Geometry;
这样当我使用 Geometry 时,我可以写
Result : Path; -- Easy to understand!
如何创建类型 'Path',它只是 Ada.Containers.Vectors.Vector 的别名?
我意识到我可以创建 OOP 风格的 'Private Type Path' 并实现所有管道以复制 Vectors 函数,但它看起来非常笨拙。
Vector
类型是 tagged
类型,这意味着您需要类型扩展而不仅仅是派生:
type Path is new Path_Points.Vector with null record;
我猜编译器在错误消息中暗示了这一点?
编辑:在下面的评论拖到更长的讨论之前,让我澄清一些困惑:
类型在 Ada 中没有名称,只有子类型有,所以类型声明(包括类型派生,创建新类型)
实际上是一个匿名类型的声明,连同它的 first subtype
.
派生类型继承基类型的基本操作,就好像它们是用新类型声明的一样。
它们仅通过显式类型转换与基类型兼容,因此您不能调用这些操作
基类型与派生类型作为参数而无需转换。很少需要那个,
但是,因为操作是继承的。
另一方面,子类型作为基本类型的重命名(它们也可以有约束,但这不在讨论范围内),
并且不继承原始操作,但必须依赖基类型进行操作。另一方面,他们是
与基本类型兼容(无需类型转换)。
因此
type Foo is null record;
procedure Process(Item : in out Foo);
概念上是:
type @anonymous_type is null record;
procedure Process(Item : in out @anonymous_type);
subtype Foo is @anonymous_type;
和
type Bar is new Foo;
概念上是:
type @derived_type is new @anonymous_type;
procedure Process(Item : in out @derived_type); -- implicit declaration of inherited subprogram
subtype Bar is @derived_type;
而
subtype Baz is Foo;
就是这样。一个新名字。
当类型在外部派生或子类型化时,所有这些的实际意义都会发挥作用
他们自己的范围,
with Ada.Strings.Unbounded;
package Foo is
subtype Bar is Ada.Strings.Unbounded.Unbounded_String;
-- Bar is a subtype; no inheritance, must call operations on the base type
Foobar : constant Bar := Ada.Strings.Unbounded.To_Unbounded_String("Foobar");
type Baz is new Ada.Strings.Unbounded.Unbounded_String;
-- Baz is a derived type, inherited operations are directly visible in its scope
Foobaz : constant Baz := To_Unbounded_String("Foobaz");
-- However:
-- This is not legal for a subtype (without a `use` clause):
-- Foobar : constant Bar := To_Unbounded_String("Foobar");
-- This is not legal for a derived type (without an explicit type conversion):
-- Foobaz : constant Bar := Ada.Strings.Unbounded.To_Unbounded_String("Foobaz");
end Foo;
现在很清楚,派生类型可以显着减少包内部所需的类型(即使没有 use
子句)。
同样,派生类型可以减少所需的类型,以及 API:
的任何用户所需的依赖项(以及可能的 use
子句)的数量
注意子类型如何强制用户with
基类型的范围
with Foo;
with Ada.Strings.Unbounded;
procedure Bar_Test is
Bar : Foo.Bar := Ada.Strings.Unbounded.To_Unbounded_String("Foobar");
-- illegal for a subtype
-- Bar : Foo.Bar := Foo.To_Unbounded_String("Foobar");
begin
null;
end Bar_Test;
派生类型不存在的地方
with Foo; -- Baz is a derived type, inherited operations are visible in Foo
procedure Baz_Test is
Baz : Foo.Baz := Foo.To_Unbounded_String("Foobaz");
-- illegal for a derived type, type conversion needed
-- Baz : Foo.Baz := Ada.Strings.Unbounded.To_Unbounded_String("Foobaz");
begin
null;
end Baz_Test;
类型扩展被定义为派生类型的一种特殊情况,其中基本类型是标记记录类型,
使我们能够扩展包含更多成员的记录:
type Foo is tagged
record
M1 : Natural;
end record;
procedure Process(Item : in out Foo);
type Bar is new Foo with
record
M2 : Natural; -- Bar has both members M1 and M2
end record;
-- implicit declaration of Process for Bar, unless Process is overridden (as for Baz below)
type Baz is new Foo with null record; -- no new members, Baz has only M1
overriding
procedure Process(Item : in out Baz); -- Process is overridden
overriding
关键字是可选的,但建议使用。
还有一个类似的not overriding
来避免意外覆盖
标记类型和类型扩展还可以在 class 类型
上启用动态调度
Dispatch : Foo'Class := Baz'(Foo with M1 => 1337);
Foo'Class
称为 class 宽类型,可以包含 Foo
或任何以 Foo
为根的类型(derived/extended 来自 Foo
)
它们还启用了更高级的功能,例如 interface
形式的多重继承,
子程序的前缀视图(更好地称为 Object.Dot 符号)、受控类型等
我正在尝试创建一个类型 'Path',它是一个点向量:
with Ada.Containers.Vectors;
use Ada.Containers;
package Geometry is
type Point is record
North : Integer := 0; -- millimetres
East : Integer := 0;
end record;
function Same_Point (A, B : Point) return Boolean is
(A.North = B.North and then A.East = B.East);
package Path_Points is new Vectors
(Element_Type => Point,
Index_Type => Positive,
"=" => Same_Point);
use Path_Points;
-- works, but poor readability. 'result' is a 'path', not a vector
Result : Vector;
-- What I'd like to do, a type called 'Path':
type Path is new Path_Points.Vector; -- WRONG
end Geometry;
这样当我使用 Geometry 时,我可以写
Result : Path; -- Easy to understand!
如何创建类型 'Path',它只是 Ada.Containers.Vectors.Vector 的别名?
我意识到我可以创建 OOP 风格的 'Private Type Path' 并实现所有管道以复制 Vectors 函数,但它看起来非常笨拙。
Vector
类型是 tagged
类型,这意味着您需要类型扩展而不仅仅是派生:
type Path is new Path_Points.Vector with null record;
我猜编译器在错误消息中暗示了这一点?
编辑:在下面的评论拖到更长的讨论之前,让我澄清一些困惑:
类型在 Ada 中没有名称,只有子类型有,所以类型声明(包括类型派生,创建新类型)
实际上是一个匿名类型的声明,连同它的 first subtype
.
派生类型继承基类型的基本操作,就好像它们是用新类型声明的一样。 它们仅通过显式类型转换与基类型兼容,因此您不能调用这些操作 基类型与派生类型作为参数而无需转换。很少需要那个, 但是,因为操作是继承的。
另一方面,子类型作为基本类型的重命名(它们也可以有约束,但这不在讨论范围内), 并且不继承原始操作,但必须依赖基类型进行操作。另一方面,他们是 与基本类型兼容(无需类型转换)。
因此
type Foo is null record;
procedure Process(Item : in out Foo);
概念上是:
type @anonymous_type is null record;
procedure Process(Item : in out @anonymous_type);
subtype Foo is @anonymous_type;
和
type Bar is new Foo;
概念上是:
type @derived_type is new @anonymous_type;
procedure Process(Item : in out @derived_type); -- implicit declaration of inherited subprogram
subtype Bar is @derived_type;
而
subtype Baz is Foo;
就是这样。一个新名字。
当类型在外部派生或子类型化时,所有这些的实际意义都会发挥作用 他们自己的范围,
with Ada.Strings.Unbounded;
package Foo is
subtype Bar is Ada.Strings.Unbounded.Unbounded_String;
-- Bar is a subtype; no inheritance, must call operations on the base type
Foobar : constant Bar := Ada.Strings.Unbounded.To_Unbounded_String("Foobar");
type Baz is new Ada.Strings.Unbounded.Unbounded_String;
-- Baz is a derived type, inherited operations are directly visible in its scope
Foobaz : constant Baz := To_Unbounded_String("Foobaz");
-- However:
-- This is not legal for a subtype (without a `use` clause):
-- Foobar : constant Bar := To_Unbounded_String("Foobar");
-- This is not legal for a derived type (without an explicit type conversion):
-- Foobaz : constant Bar := Ada.Strings.Unbounded.To_Unbounded_String("Foobaz");
end Foo;
现在很清楚,派生类型可以显着减少包内部所需的类型(即使没有 use
子句)。
同样,派生类型可以减少所需的类型,以及 API:
的任何用户所需的依赖项(以及可能的use
子句)的数量
注意子类型如何强制用户with
基类型的范围
with Foo;
with Ada.Strings.Unbounded;
procedure Bar_Test is
Bar : Foo.Bar := Ada.Strings.Unbounded.To_Unbounded_String("Foobar");
-- illegal for a subtype
-- Bar : Foo.Bar := Foo.To_Unbounded_String("Foobar");
begin
null;
end Bar_Test;
派生类型不存在的地方
with Foo; -- Baz is a derived type, inherited operations are visible in Foo
procedure Baz_Test is
Baz : Foo.Baz := Foo.To_Unbounded_String("Foobaz");
-- illegal for a derived type, type conversion needed
-- Baz : Foo.Baz := Ada.Strings.Unbounded.To_Unbounded_String("Foobaz");
begin
null;
end Baz_Test;
类型扩展被定义为派生类型的一种特殊情况,其中基本类型是标记记录类型, 使我们能够扩展包含更多成员的记录:
type Foo is tagged
record
M1 : Natural;
end record;
procedure Process(Item : in out Foo);
type Bar is new Foo with
record
M2 : Natural; -- Bar has both members M1 and M2
end record;
-- implicit declaration of Process for Bar, unless Process is overridden (as for Baz below)
type Baz is new Foo with null record; -- no new members, Baz has only M1
overriding
procedure Process(Item : in out Baz); -- Process is overridden
overriding
关键字是可选的,但建议使用。
还有一个类似的not overriding
来避免意外覆盖
标记类型和类型扩展还可以在 class 类型
上启用动态调度Dispatch : Foo'Class := Baz'(Foo with M1 => 1337);
Foo'Class
称为 class 宽类型,可以包含 Foo
或任何以 Foo
为根的类型(derived/extended 来自 Foo
)
它们还启用了更高级的功能,例如 interface
形式的多重继承,
子程序的前缀视图(更好地称为 Object.Dot 符号)、受控类型等