- 第一章 Fortran 语言程序设计初步
- 第二章 改变程序流程
- 第三章 循环结构
- 第四章 数据结构
- 第五章 数组
- 第六章 过程和模块
- 第七章 输入输出和文件
4.3.2 派生类型
为了便于组织数据,F90 允许定义和使用派生数据类型。任何复杂的数据结构,经分析后都可分解为较简单的成员,可用自定义的派生类型反映它。派生数据类型有一个类型名称,它不能和任何内部数据类型或已定义的派生数据类型重名。定义一种派生数据类型后就可以用它来定义变量、命名常量或其它派生类型了。
a) 派生类型定义
定义派生类型时必须使用 TYPE 块。TYPE 块应写在程序的说明部分中,通常写在说明的前部,其一般形式是:
TYPE[,访问属性说明::] 派生类型名
成员 1 类型说明
……
成员 n 类型说明
END TYPE [派生类型名]
其中,TYPE 是关键字,表示派生类型定义开始。访问属性说明关键字是 PUBLIC 或 PRIVATE,默认值是 PUBLIC,即访问方式是共用的。PRIVATE 表示该类型是专用的,这个关键字只有当 TYPE 块写在模块说明部分中时,才允许使用。如果不是在模块内定义的派生类型,不可使用 PRTVATE。派生类型名是任意取的,一旦定义完成,该类型名就成为一个新的类型,就像整型、实型、逻辑型等一样,按一种类型使用。例如可以把各种变量、各种数组说明为这种新的类型,而后按新类型特有法则操作。通常,类型的取名与物理对象的名称一致。例如上述学生结构定义成派生类型可以取派生类型名是 STUDENT。
TYPE 语句下面是结构中各成员的类型说明语句,被说明的类型一般就是 FORTRAN 内部类型(整型、实型等),也允许用一个层次较低的派生类型作为某成员的类型。派生类型的说明语句的一般形式是:TYPE(派生类型名)::变量名。TYPE 块中只有类型说明语句,不允许有可执行的动作语句。派生类型中字符型成员不可取*为长度,必须是确定长度。系统不一定会按定义时的顺序储存各个成员,除非在定义中包含有 SEQUENCE 语句。
例如:对上面的学生记录作派生定义,由于学生结构中有两个成员 CLASS 与 SCORES 本身又是次一层的结构,因此要先对 CLASS 与 SCORES 这两个结构作出派生类型定义。CLASS 下有两个成员:DEPARTMENT(字符型)、MAJOR(字符型)。SCORES 下有三个成员:MATH(整型)、PHYSICS(整型)、ENGLISH(整型)。整个学生结构定义派生类型名为 STUDENT_TYPE。
TYPE CLASS_TYPE
CHARACTER(LEN=50) :: DEPARTMENT, MAJOR
END TYPE CLASS_TYPE
TYPE SCORES_TYPE
INTEGER(1) :: MATH, PHYSICS, ENGLISH
END TYPE SCORES_TYPE
TYPE STUDENT_TYPE
SEQUENCE
INTEGER(4) :: NUMBER
TYPE(CLASS_TYPE) :: CLASS
CHARACTER(LEN=10) :: NAME, ADDRESS
TYPE(SCORES_TYPE) :: SCORES
END TYPE STUDENT_TYPE
TYPE(STUDENT_TYPE),DIMENSION(40):: STUDENT
注意在上面三个定义派生类型 TYPE 语句中,派生类型名取成‘名_TYPE’形式,这是为了加强可读性。特别是当它的成员名与类型名一致时,可以这样区分。当给定属性 DIMENSION(40) 后,STUDENT 即为有 40 个学生的派生型数组,每个学生按顺序有学号、班级(系、专业)、姓名、地址、成绩(数学、物理、英语) 等成员。
b) 缺省初始化
F95 中,允许定义派生数据类型成员时给予初始值,这时就有了缺省初始化,但没有必要为每一个成员指定初始值。它的显式初始化会覆盖缺省初始化。例如:
TYPE REPORT
CHARACTER (LEN=20) REPORT_NAME
INTEGER DAY
CHARACTER (LEN=3) MONTH
INTEGER :: YEAR = 1999 ! 年份这个成员有缺省初始值
END TYPE REPORT
而下面语句中,显式的初始化覆盖了 NOV_REPORT 中的 YEAR 成员。
TYPE(REPORT),PARAMETER :: NOV_REPORT=REPORT("Sales",15,"NOV",2001)
又如,下面用 DATA 语句进行显式初始化:
TYPE EMPLOYEE
INTEGER ID
CHARACTER(LEN=40) NAME
END TYPE EMPLOYEE
TYPE(EMPLOYEE) MAN_NAME,CON_NAME
DATA MAN_NAME/EMPLOYEE(417,'Henry Adams')/
DATA CON_NAME%ID,CON_NAME%NAME /891,"David James"/
c) 结构构造函数
F90 有一种与结构有关的函数,称为结构构造函数,它用来给某结构类型中一个具体的变量赋值。定义了一个派生类型,实际上也同时建立了一个结构构造函数,这个函数名就是派生类型名,函数的自变量就是派生类型内各成员。只要派生类型一建立,就可直接调用这个结构构造函数。如果把实在的各成员值作为实元,与结构构造函数中自变量作哑实结合,其函数值就是被定义成派生类型的一个变量的值,可以直接赋给派生类型中的某一变量名。例如,对下面的派生类型:
TYPE FRIEND_TYPE
CHARACTER(LEN=20) :: NAME
INTEGER :: AGE
END TYPE FRIEND_TYPE
系统中就自动生成一个函数名叫 FRIEND_TYPE 的结构函数,该函数有两个哑元自变量:NAME、AGE。其完整的函数形式为:FRIEND_TYPE(NAME,AGE)。假设变量名 MY_FRIEND 被说明为 FRIEND_TYPE 类型,即程序中有说明语句:
TYPE(FRIEND_TYPE) :: MY_FRIEND, MY_BOY_FRIEND, MY_GIRL_FRIEND
于是可把‘Kong Ming’作为 NAME 的实元,25 作为 AGE 的实元,在程序执行部分中调用结构构造函数,并把函数值赋给变量 WHO,赋值语句为:MY_FRIEND=FRIEND_TYPE(‘Kong Ming’,25)。此时具有 FRIEND_TYPE 类型的变量 MY_FRIEND 就有了 NAME 成员值和 AGE 成员值。
调用结构构造函数作哑实结合时,只要保持类型、个数、位置一致,可以有多种形式的实元与哑元结合。譬如实元可以又是另一低层次结构的结构构造函数,或另一个结构的成员等。如回到前面较复杂的学生结构例中,设已定义派生类型 STUDENT_TYPE,并说明了变量名 ZHANG_FEI 是 STUDENT_TYPE 类型的,而后我们在执行部分中对 ZHANG_FEI 的成员 CLASS 通过如下赋值语句赋值:
ZHANG_FEI%CLASS=CLASS_TYPE(‘22th Department’,‘Applied Physics’)
这里引用 CLASS_TYPE 的结构构造函数,说明变量 ZHANG_FEI 的班级是 22 系应用物理专业,也即 ZHANG_FEI%CLASS 已经有定义。因此接着可以把 ZHANG_FEI%CLASS 作为结构构造函数 STUDENT_TYPE 的实元,把整个函数值赋给变量 ZHANG_FEI:
ZHANG_FEI=STUDENT_TYPE(0022123,ZHANG_FEI%CLASS,&
‘ZHANG_FEI’,‘He Fei’,SCORES_TYPE(82,73,90))
使用结构构造函数可以非常方便地给具有这种结构的变量赋值,如果若干变量形成一个数组,就可打印出一份详细的档案,并可按照需要排序及检索。
d) 应用
例:利用成员特征作排序检索。如果上面 40 个学生姓名和成绩已经读入,要查找名叫张飞的成绩并打印输出,并列出数学成绩在 85 分以上的名单。将前面的派生类型定义简化后为:
PROGRAM STUDENT_IO
TYPE SCORES_TYPE
INTEGER(1) :: MATH, PHYSICS, ENGLISH
END TYPE SCORES_TYPE
TYPE STUDENT_TYPE
CHARACTER(LEN=10) :: NAME
TYPE(SCORES_TYPE) :: SCORES
END TYPE STUDENT_TYPE
TYPE(STUDENT_TYPE),DIMENSION(40):: STUDENT
READ‘(A,3I3)’, STUDENT
DO I=1,40
IF(STUDENT(I)%NAME=‘Zhang Fei’) PRINT *,STUDENT(I)%SCORES
END DO
DO I=1,40
IF(STUDENT(I)%SCORES%MATH>=85) PRINT *,STUDENT(I)%NAME
END DO
END PROGRAM STUDENT_IO
例:建立一个计算机帐户的数据库,根据用户号码查找其帐上余额并显示。 [e_432_01.f90]
例:建立一个学生的数据库,包含有学生姓名和考分的记录。从键盘上输入这些记录,并将它们放入一直接存取的文件中,要求可以显示、增加和修改记录。 [e_432_02.f90]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论