类型和子类型
Example program ------> e_c03_p4.ada
-- Chapter 3 - Program 4 with Ada.Text_IO, Ada.Integer_Text_IO; use Ada.Text_IO, Ada.Integer_Text_IO; procedure SubTypes is type MY_INT_TYPE is range -10_000..20_000; My_Int : MY_INT_TYPE; package My_Int_IO is new Ada.Text_IO.Integer_IO(MY_INT_TYPE); use My_Int_IO; subtype SUB_INT is INTEGER range 12..144; Thing : SUB_INT; Count : INTEGER; Stuff : INTEGER range 12..144; START : constant := 4; -- START is 4 STOP : constant := START + 13; -- STOP is 17 Example : SUB_INT range 4*START..2*STOP + 7; -- 16..41 Example2 : MY_INT_TYPE range START..2*STOP + 7; -- 4..41 begin Thing := 6 * 3; -- Thing is 18 Count := Thing + 17; -- Count is 35 Stuff := Count - Thing; -- Stuff is 17 My_Int := 6 * 3; -- My_Int is 18 My_Int := MY_INT_TYPE(Thing + 17); -- My_Int is 35 My_Int := MY_INT_TYPE(Thing) + 17; -- My_Int is 35 My_Int := MY_INT_TYPE(Thing) - 10; -- My_Int is 8 My_Int := MY_INT_TYPE(Thing - 10); -- Run Time Error My_Int := 35; Thing := SUB_INT(My_Int - 17); -- Thing is 18 Thing := SUB_INT(My_Int - 27); -- Run Time Error Example := Thing + SUB_INT(My_Int); end SubTypes; -- Result of execution -- Exception never handled: constraint_error -- Value 8 out of range 12..144.
查看上面程序,以便了解您第一次查看用户自定义的类型。我们前面提到过,整数类型变量的范围可能在不同的计算机上不同,或者同一台计算机上的编译器不同。Ada使我们能够定义自己的类型,这样它将在每台计算机和每个Ada编译器上是相同的。
不同类型不兼容
第7行定义了一个新的整数类型,它将覆盖-10000到20000的范围,因为使用了保留字range来限制可以分配给这种类型的变量的值的可用范围。请注意,我们称之为integer类型,而不是INTEGER类型,两者是有区别的。因为它是整数类型,所以它具有整型定义的所有属性,但是只能为这种类型的变量赋值-10000到20000之间的值。实际范围通过指定由两个小数点分隔的下限和上限来给出。
实际上我们已经定义了一个全新的类型,由于Ada做了非常强的类型检查,它将不允许您将INTEGER类型的变量中的值直接赋给我们新类型的变量,反之亦然。变量my_Int是用第8行中的新类型定义的。我们稍后再考虑这个变量。
第10行中的包声明对我们来说是全新的,所以有一些关于它的评论。我们将首先给出Ada术语中第10行的完整定义,包括许多新词,这些新词目前对您来说意义不大,直到您获得本教程后面将给出的一些附加知识。第10行是创建一个新的名为MY_INT_TYPE的包,类型为Ada.Text_IO.Integer_IO,可将MY_INT_TYPE的值输出到监视器或文件,或从键盘或文件输入。用一种更有用的方式说同样的话,如果您想输入或输出除预定义类型INTEGER以外的某个整型类类型的值,则必须在括号中包含所需类型所示的行。包括11号线是为了使新的软件包易于使用。您将注意到,它告诉系统使用紧跟在关键字package后面的第10行中命名的包。
如前所述,为了简化Ada的学习曲线,有些主题会推迟到以后,让你有机会一次吸收几个主题,所以现在不要花任何时间试图理解前一段。
新的子类型与其父类型兼容
在第13行中,我们定义了一个新的子类型,它是父类型INTEGER,只是它覆盖了一个有限的范围,然后在第14行中声明了一个名为Thing的变量。任何试图给变量赋值的行为如果超出了它的赋值范围,都会导致错误。如果你经营一家有23名员工的小公司,你给每个员工分配了一个从1到23的唯一数字,那么你会对程序是否试图为编号为36的员工生成工资单感兴趣,显然,肯定会出问题。在这种情况下,一个有限的子范围可以为你节省很多钱。
赋值必须与类型兼容
任何时候一个值被分配给一个变量,分配给它的类型必须是它声明的类型,否则将生成一个编译器错误。这在Ada中始终是正确的,并且是其设计背后最重要的概念之一。这是为了防止我们犯我们人类擅长犯的愚蠢的小错误。
变量Count被定义为整数类型的变量,Stuff也被定义为有限范围的整数。记住,Thing被声明为INTEGER的子类型,所以它也是一个有限范围的INTEGER类型变量。由于这三个变量的定义方式,只要赋值在各自的范围内,就可以*地相互赋值。这是因为它们都是同一个父类型INTEGER,它们之间的各种赋值如第25行到第27行所示。
如果我们试图将Thing的值赋给My_Int,计算机会给出一个编译错误,因为它们的类型不同,但是可以使用显式类型转换来进行赋值,如第30行所示。通过在括号中包含要转换为新类型的变量,并在括号前面加上所需的类型名称,系统将转换类型,如图所示。对Thing的添加完成,括号内的整个表达式通过显式类型转换在类型中更改为赋值语句左侧所需的类型。请注意,显式类型转换只能从同一类型类(在本例中是integer类)中完成。
在第31行中,在将值17添加到该类型之前,该类型将更改为新类型,这将导致您询问有关常量17的类型的问题。
如何将17添加到任一类型?
常量17是一种非常特殊的类型,由Ada定义为“universal_integer”类型,它可以与任何整数类型组合而无需特定转换。这一术语将在以后的课程中以多种方式使用。类型universal_integer与所有整数类型兼容,并且其范围没有限制。范围实际上是从负无穷大到正无穷大。类型universal_integer用于所有文字值,但在声明变量时不可用。
现在是子范围错误
第30行和第31行基本上是相同的,因为它们得到相同的答案,第33行和第34行看起来是相同的,但它们不是。在第33行中,Thing的值是18,它被转换成my_INT类型,然后从中减去10。18和8都在my_INT类型的指定范围内,因此没有错误。然而,在第34行中,减法的结果具有事物的类型,甚至中间结果也必须在12到144的范围内。8的结果超出了所需的范围,因此运行时错误将以一种称为引发异常的特殊方式发出信号。我们将很快讨论这个异常,但首先要注意的是,如果我们能够克服这个错误,我们可以将结果的类型更改为MY_INT_TYPE,并且一切都将按预期工作。
中间计算结果
ARM标准允许根据父类型的限制而不是子类型的限制检查中间结果的限制。因此,行34不能给出指示中间结果超出允许范围的错误。这将取决于您的编译器。
什么是异常?
在我们完成本教程的过程中,我们将有很多关于异常的介绍,但是此时需要进行非常简短的描述。当Ada程序正在运行,并且检测到潜在的灾难性错误时,程序员能够告诉系统如何处理错误,而不是导致程序的完全终止,这对您来说是有益的。Ada通过使用您编写和包含在程序中的异常处理程序,为您提供了这种功能。在上述情况下,当程序检测到8的值超出该类型变量的允许范围时,它将向程序发出错误的信号,如果您没有做任何操作,Ada系统将终止程序。信令的适当Ada术语称为“引发异常”,在超出界限值的情况下,将引发名为Constraint_error的异常。然后,您可以捕获此错误并以任何方式处理它。
系统可以引发几个不同的异常,您可以定义自己的程序可以引发和响应的异常。在本教程后面的部分中,我们将有更多关于异常的内容。
知道这些后应该可以揭示为什么第38行还有一个运行时错误,如果继续执行该语句,它将引发Constraint_error错误。
再看一下universal_integer 这个类型
在我们离开这个程序之前,我们必须先看看第18行和第19行,在那里我们首先定义START和STOP为常量,没有类型指示。因此,这些常量属于“universal_integer”类型,可以在下两行的范围定义中使用,即使这两行的父类型不同。如果我们在第18行和第19行的定义中包含了INTEGER这个词,那么它们就不能用来定义Example2的限制,因为它的类型不同。名为e_c03_p3.ada的示例程序有整数常量(tike和GROSS)和通用整数类型常量(BIG_NO和TWO)。类型universal_integer实际上是一个隐藏类型,它的类型与所有整数类型兼容。
还应注意的是,这些定义中的范围限制是基于先前定义的实体,只要它们的计算类型正确,就可以具有任意的复杂性。限制也必须在父类型的范围内,否则将导致编译错误。
如何定义类型和子类型
要声明类型或子类型,可以遵循以下两个简单公式。
type <type_name> is <type_definition>; subtype <subtype_name> is <subtype_definition>;
注意,每个声明都以保留词开头,并包含保留词,该词位于名称和定义之间。应该指出,只要在使用之前定义了所有内容,Ada就允许以任何顺序执行新类型、子类型和变量声明。
编译并执行e\_c03_p4.ada,观察运行时系统报告的异常错误。根据编译器的不同,在第34行可能会引发异常,其中8的值超出了12到144的允许范围。错误消息会因编译器的不同而不同。
更多关于类型和子类型的内容将在本教程的第7章中介绍。
什么是属性?
Example program ------> e_c03_p5.ada
-- Chapter 3 - Program 5 with Ada.Text_IO, Ada.Integer_Text_IO; use Ada.Text_IO, Ada.Integer_Text_IO; procedure IntAttrs is type BUG_RANGE is range -13..34; Rat : INTEGER; Dog : NATURAL; Cat : POSITIVE; Bug : BUG_RANGE; begin Rat := 12; Dog := 23; Cat := 31; Bug := -11; Put("The type INTEGER uses "); Put(INTEGER'SIZE); Put(" bits of memory,"); New_Line; Put(" and has a range from "); Put(INTEGER'FIRST); Put(" to "); Put(INTEGER'LAST); New_Line; Put(" Rat has a present value of "); Put(Rat); New_Line(2); Put("The type NATURAL uses "); Put(NATURAL'SIZE); Put(" bits of memory,"); New_Line; Put(" and has a range from "); Rat := NATURAL'FIRST; Put(Rat); Put(" to "); Rat := NATURAL'LAST; Put(Rat); New_Line; Put(" Dog has a present value of "); Put(Dog); New_Line(2); Put("The type POSITIVE uses "); Put(POSITIVE'SIZE); Put(" bits of memory,"); New_Line; Put(" and has a range from "); Put(POSITIVE'FIRST); Put(" to "); Put(POSITIVE'LAST); New_Line; Put(" Cat has a present value of "); Put(Cat); New_Line(2); Put("The type BUG_RANGE uses "); Put(INTEGER(BUG_RANGE'SIZE)); Put(" bits of memory,"); New_Line; Put(" and has a range from "); Put(INTEGER(BUG_RANGE'FIRST)); Put(" to "); Put(INTEGER(BUG_RANGE'LAST)); New_Line; Put(" Bug has a present value of "); Put(INTEGER(Bug)); New_Line(2); end IntAttrs; -- Result of execution -- The type INTEGER uses 32 bits of memory, -- and has a range from -2147483648 to 2147483647 -- Rat has a present value of 12 -- The type NATURAL uses 31 bits of memory, -- and has a range from 0 to 2147483647 -- Dog has a present value of 23 -- The type POSITIVE uses 31 bits of memory, -- and has a range from 1 to 2147483647 -- Cat has a present value of 31 -- The type BUG_RANGE uses 7 bits of memory, -- and has a range from -13 to 34 -- Bug has a present value of -11
Ada有一个相当大的属性列表,可以作为编程辅助工具。对于一个包含属性并因此说明了属性用法的程序示例,请检查程序。
第7行定义了一个新的类型,其范围有限,以说明即使对于用户定义的类型,属性也是可用的。
第10行和第11行中引入了两个额外的预定义整数类型,即自然类型和正类型。正类型包括所有大于或等于1的整数,自然类型包括所有大于或等于0的整数。这两种类型都可以在Ada编译器中使用,而且都是INTEGER的子类型,因此这三种类型的所有变量都可以*混合,没有类型错误。
属性用于访问程序中的各种限制。例如,可能需要知道某个类型变量的上限,因为它是一些奇怪的子类型。属性可以用来找到这个限制,特别是这个程序第28行中所示的最后一个属性LAST。通过将类型名称和相关属性与“勾号”或撇号相结合,返回类型范围的上限。属性FIRST用于查找子范围允许的最低值。属性大小SIZE以内存位表示类型的存储大小。其他属性可用于整数类型。ARM附件K中给出了可用属性的完整列表。你应该花几分钟时间来复习一下清单,尽管你对那里的内容几乎不了解。在不久的将来,你将了解其中的大部分材料。
类型转换
请注意第63、67、69和72行中的类型转换。BUG_RANGE type可以通过实例化Ada.Text_Integer_IO的方式与示例程序e_c03_p4.ada中的方式类似,但我们选择使用类型转换,而不是实例化I/O包的新副本。因为NATURAL和POSITIVE是INTEGER的子类型,所以它们使用Ada系统为INTEGER类型预先实例化的I/O包的副本。
编译并运行此程序,您将得到编译器存储四种类型中的每一种所需的位数以及四种类型中的每个类型所涵盖的范围的列表。
编程练习
1.写一个包含一些限制的类型的程序,看看当你超过它们的限制时会发生什么错误 (Solution)
2.尝试给一些变量分配一些错误的数据类型,并尝试在算术语句中混用一些类型。研究编译器错误消息。 (Solution)
3.修改e_c03_p5.ada,通过实例化泛型包的新副本,直接输出BUG_RANGE属性Ada.Text_IO.Integer_ IO。在看答案之前,不要在这个练习上花太多时间。它包含一个新的构造,至少对您来说是新的 (Solution)
---------------------------------------------------------------------------------------------------------------------------
原英文版出处:https://perso.telecom-paristech.fr/pautet/Ada95/a95list.htm
翻译(百度):博客园 一个默默的 *** 的人