派生类型的可变长度数组
variable length array in derived type
我主要在 Python 中进行科学编程,并没有很多 Fortran (90/95) 经验。对于我的一个项目,我想定义一个派生类型并为该类型重载一堆运算符。至关重要的是,我希望派生类型的变量之一为可变长度的数组;至少,我需要在代码的不同部分使用两种不同的长度。我怎样才能最有效地实现这一目标并避免代码重复?
我的第一种方法是使用可分配数组,但在整个代码中涉及多个分配语句,包括重载运算符。这也导致在 MPI 应用程序中使用代码时遇到困难。
我目前的方法是在两个单独的模块中定义同名的类型,并在代码的不同部分使用一个或另一个。可以使用头文件共享重载运算符(下例中的 mytype_operators.h
)。
module mod1
type mytype
real :: x1
real,dimension(1) :: x2
end type mytype
#include "mytype_operators.h"
end module mod1
module mod2
type mytype
real :: x1
real,dimension(10) :: x2
end type mytype
#include "mytype_operators.h"
end module mod2
不幸的是,代码中有一个模块包含我想用于这两种类型的子例程。目前我有两份该代码;一个带有“use mod1
”,另一个带有“use mod2
”。我可以改进它并避免代码重复吗?
您的案例非常适合使用名为 parameterized derived types 的 2003 标准中引入的 Fortran 功能(并在很久以后被编译器采用)。首先,您应该检查编译器的合规性状态,了解它是否完全受支持。
此功能允许您在声明或构造派生类型时传递自定义参数,因此内部功能将相应调整。它们适用于将不同的行为选项分组到一个类型名称中,可能具有相当大的编码或存储差异。有两种类型的参数:
kind
参数的行为很像内在类型的种类说明符。所有变量的种类参数必须在编译时已知,并且实际上被视为常量值。方便之处在于您可以通过仅更改声明或构造中的值来轻松地(在代码时间)更改它。这通常用于专门化内部类型的组件。
len
参数的行为很像固有字符类型的 len 说明符。您可以在编译时或运行时定义 len 参数,并且变量的 len 参数不能更改,除非您将其声明为可分配的。此外,您可以在过程中使用假定的 len 参数进行参数,并避免代码冗长。这通常用作派生类型的 "length" 或 "dimension" 参数,因为您可以在数组边界和字符长度的声明中使用它们。
一般来说,类型参数用于模仿派生类型中固有类型的功能,但您也可以得到 "creative" 并将其用于其他用途,例如维度 -space转换矩阵类型;对于自定义 "union type"(如枚举);作为 "units of measurement" 数据类型中物理量的性质(用 "mass" 统一注释的实数值与 "temperature" 不直接兼容,但它们几乎可以处理代码中的相同方式);元组类型的 "arity"...
module mod1
type :: mytype(n)
integer, len :: n
real :: x1
real, dimension(n) :: x2
end type mytype
contains
! your operations here...
end module mod1
并像这样使用它:
program test_pdt
use mod1
implicit none
type(mytype(10)) :: mt10
type(mytype(1)) :: mt1
integer :: i
mt10%x1 = 40.0
mt10%x2 = [(0.5 * i, i = 1, 10)]
mt1 = mytype(1)(20.0, [30.0])
call sub(mt10)
call sub1(mt1)
contains
subroutine sub(m)
! accepts values with any "n" parameter
type(mytype(*)) :: m
! you can also use them in declarations
integer, dimension(m%n + 1) :: y
type(mytype(m%n)) :: w
print *, m%n, w%n, size(y)
end
subroutine sub1(m)
type(mytype(1)) :: m ! only accepts values with n=1
print *, m%x1, m%x2, m%n
end
end
警告:
这是一个功能,尽管多年前就已宣布,但最近才被添加到大多数编译器中,您应该知道在实现过程中仍然存在一些错误。经常使用你应该没问题,但我经常在一些极端情况下遇到错误的语法错误,有时甚至是 ICE。
我主要在 Python 中进行科学编程,并没有很多 Fortran (90/95) 经验。对于我的一个项目,我想定义一个派生类型并为该类型重载一堆运算符。至关重要的是,我希望派生类型的变量之一为可变长度的数组;至少,我需要在代码的不同部分使用两种不同的长度。我怎样才能最有效地实现这一目标并避免代码重复?
我的第一种方法是使用可分配数组,但在整个代码中涉及多个分配语句,包括重载运算符。这也导致在 MPI 应用程序中使用代码时遇到困难。
我目前的方法是在两个单独的模块中定义同名的类型,并在代码的不同部分使用一个或另一个。可以使用头文件共享重载运算符(下例中的 mytype_operators.h
)。
module mod1
type mytype
real :: x1
real,dimension(1) :: x2
end type mytype
#include "mytype_operators.h"
end module mod1
module mod2
type mytype
real :: x1
real,dimension(10) :: x2
end type mytype
#include "mytype_operators.h"
end module mod2
不幸的是,代码中有一个模块包含我想用于这两种类型的子例程。目前我有两份该代码;一个带有“use mod1
”,另一个带有“use mod2
”。我可以改进它并避免代码重复吗?
您的案例非常适合使用名为 parameterized derived types 的 2003 标准中引入的 Fortran 功能(并在很久以后被编译器采用)。首先,您应该检查编译器的合规性状态,了解它是否完全受支持。
此功能允许您在声明或构造派生类型时传递自定义参数,因此内部功能将相应调整。它们适用于将不同的行为选项分组到一个类型名称中,可能具有相当大的编码或存储差异。有两种类型的参数:
kind
参数的行为很像内在类型的种类说明符。所有变量的种类参数必须在编译时已知,并且实际上被视为常量值。方便之处在于您可以通过仅更改声明或构造中的值来轻松地(在代码时间)更改它。这通常用于专门化内部类型的组件。len
参数的行为很像固有字符类型的 len 说明符。您可以在编译时或运行时定义 len 参数,并且变量的 len 参数不能更改,除非您将其声明为可分配的。此外,您可以在过程中使用假定的 len 参数进行参数,并避免代码冗长。这通常用作派生类型的 "length" 或 "dimension" 参数,因为您可以在数组边界和字符长度的声明中使用它们。
一般来说,类型参数用于模仿派生类型中固有类型的功能,但您也可以得到 "creative" 并将其用于其他用途,例如维度 -space转换矩阵类型;对于自定义 "union type"(如枚举);作为 "units of measurement" 数据类型中物理量的性质(用 "mass" 统一注释的实数值与 "temperature" 不直接兼容,但它们几乎可以处理代码中的相同方式);元组类型的 "arity"...
module mod1
type :: mytype(n)
integer, len :: n
real :: x1
real, dimension(n) :: x2
end type mytype
contains
! your operations here...
end module mod1
并像这样使用它:
program test_pdt
use mod1
implicit none
type(mytype(10)) :: mt10
type(mytype(1)) :: mt1
integer :: i
mt10%x1 = 40.0
mt10%x2 = [(0.5 * i, i = 1, 10)]
mt1 = mytype(1)(20.0, [30.0])
call sub(mt10)
call sub1(mt1)
contains
subroutine sub(m)
! accepts values with any "n" parameter
type(mytype(*)) :: m
! you can also use them in declarations
integer, dimension(m%n + 1) :: y
type(mytype(m%n)) :: w
print *, m%n, w%n, size(y)
end
subroutine sub1(m)
type(mytype(1)) :: m ! only accepts values with n=1
print *, m%x1, m%x2, m%n
end
end
警告: 这是一个功能,尽管多年前就已宣布,但最近才被添加到大多数编译器中,您应该知道在实现过程中仍然存在一些错误。经常使用你应该没问题,但我经常在一些极端情况下遇到错误的语法错误,有时甚至是 ICE。