Ada程序包的概述
概述(Overview)
多子程序封装在一个文件里过于庞大,且分类不清,这时就使用了程序包(package),作为一种分组机制,将子程序归类封装成独立的单元。Ada 的程序包机制主要受 Pascal 及 70 年代时的软件工程技术影响。当时很主要的一项革新就是软件包的概念。软件包使一个大程序分离成了多个单元,使软件维护更加方便,可重用性也更高,是结构化编程思想中必不可少的一部份。
软件包并不关心程序是如何运行的,而是在于理解程序是如何构成的以及维护性。Ada 的程序包是定义一堆相关实体(如数据类型、运算符、子程序)的最基本单元,也是使用最常用的编译单元之一。本章里我们介绍程序包的常见用法,更多的内容,如类属程序包,请参见后面的章节。
程序包的声明(Package Declaration)
程序包一般分为两部份,声明部分和执行部份。声明部份声明子程序、变量等实体,他们通常被称为资源;而执行部份则是声明部分中实体的实现。它们的扩展名一般情况下分别为 ads 和 adb。为了省力点,我们就直接将上一章的overload 做个处理,将"+"和Put封装在程序包内,这样程序包说明如下:
000 --filename:overload.ads
001 package Overload is
002 type Vector is array (1 .. 5 ) of Integer;
003 function "+"(left,right:Vector) return Vector;
004 procedure Put (Item : Vector) ;
005 end Overload;
从这个例子,我们应该知道了程序包说明的格式:
package packgae_name is
statements;
end package_name;
statemets就是数据类型、变量、常量、子程序的声明。
程序包的主体部份(Package Body)
仅仅有说明部份,程序包还没什么用处,还要有它的主体部份,即说明部份的具体实现。主体部份可以包含创建数据类型、子程序、变量、常量。它的格式为:
package body packgae_name is
statements1;
[begin]
statements2;
end package_name;
statements1 是创建子程序、数据类型、变量、常量的语句,一般情况下是说明部份的具体实现;[begin]是可选的,它后面的statement2 是程序包的初始化语句,在主程序执行前开始执行。
所以上例 overload 的主体部分为:
000 -- filename:overload.adb
001 with Ada.Integer_Text_IO; use Ada.Integer_text_IO;
002 package body Overload is
003 function "+"(left,right:Vector) return Vector is
004 result : Vector ;
005 begin
006 for i in left'range loop
007 result(i) := left(i) + right(i);
008 end loop;
009 return result;
010 end "+";
011 procedure Put (Item : Vector) is
012 begin
013 for i in Item'range loop
014 Put (Item(i));
015 end loop;
016 end Put;
017 end Overload;
这里我们没有使用可选的 [begin] statement2,因为没有必要做一些初始化操作。下面是一些注意点:
1.主体部分内的资源不能被其它程序包所引用,会引起编译错误。
2.假如好几个程序包都有初始化语句,执行顺序是不确定的。
3.所有说明部份内的资源可以被其主体部份直接使用,无须 with 和 use 语句。
程序包的使用(Using Package)
如同我们先前使用 Ada.Text_IO 一样,使用程序包要使用 with 和 use。use 可以不用,但这样的话使用程序包麻烦很多,如 Put ,就要使用 Ada.Text_IO.Put这种详细写法;use 使编译器自动在软件包中寻找相匹配的子程序和其它资源。现在将 overload 的主程序给出:
000 -- filename: main.adb
001 with Overload; use Overload;
002 procedure Main is
003 a,b,c:Vector;
004 begin
005 a := (1,2,3,4,5);
006 b := (1,2,3,4,5);
007 c := a + b;
008 Put (c);
009 end Main;
编译 main.adb,overload.adb,overload.ads 所得的程序和以前的效果也一样。
一般情况下,with 和 use 语句在程序的首部,但 use 语句也可以在程序内部(with 语句则不能),如:
000 -- filename: main.adb
001 with Overload;
002 procedure Main is
003 use Overload;
004 a,b,c:Vector;
005 begin
006 a := (1,2,3,4,5);
007 b := (1,2,3,4,5);
008 c := a + b;
009 Put (c);
010 end Main;
这种用法很常见,特别是使用类属程序包时。以后我们会见到这方面的其它实例。
使用软件包时要注意一下变量、常量等名称的问题,如果有相同的名称,就需要详细写出所期望的资源名称,如程序包 Ada.Text_IO 的 Put 要写为 Ada.Text_IO.Put。如果在 Overload 的声明部份也加一个变量a(2,3,5,6,8),则声明部份为:
000 --filename:overload.ads
001 package Overload is
002 type Vector is array (1 .. 5 ) of Integer;
003 a: Vector := (2,3,5,6,8);
004 function "+"(left,right:Vector) return Vector;
005 procedure Put (Item : Vector) ;
006 end Overload;
同时我们希望主程序将两个不同的a分别与b相加,则 Overload 中的 a 要表示为 Overload.a,主程序变为:
00 -- filename: main.adb
001 with Overload; use Overload;
002 with Ada.Text_IO; use Ada.Text_IO;
003 procedure Main is
004 a,b,c:Vector;
005 begin
006 a := (1,2,3,4,5);
007 b := (1,2,3,4,5);
008 c := a + b;
009 Put (c);
010 New_Line;
011 c := Overload.a + b; -- Overload.a 表示程序包 Overload中的变量 a
012 Put (c);
013 New_Line;
014 end Main;
明确资源的位置在很多地方都是需要的,都是为了防止相同名称引起混淆。