Fortran 通过过程调用选择派生类型
Fortran choose derived type by procedure call
有没有办法使派生类型具有接口,以便为泛型派生类型调用特定的模块过程?我可能没有正确解释这一点,但这是我想做的简短示例代码:
module test_mod
implicit none
private
public :: type_AB ! This is what I'd like to do...
public :: init,apply,delete
interface type_AB ! This is what I'd like to do...
module type type_AB
end interface
interface init; module procedure init_A; end interface
interface init; module procedure init_B; end interface
interface apply; module procedure apply_A; end interface
interface apply; module procedure apply_B; end interface
type type_A
integer :: x
end type
type type_B
integer,dimension(3) :: x
end type
contains
subroutine init_A(AB,x)
implicit none
type(type_A),intent(inout) :: AB
integer,intent(in) :: x
AB%x = x
end subroutine
subroutine init_B(AB,x)
implicit none
type(type_B),intent(inout) :: AB
integer,dimension(3),intent(in) :: x
AB%x = 2
end subroutine
subroutine apply_A(AB,x)
implicit none
type(type_A),intent(inout) :: AB
integer,intent(in) :: x
AB%x = AB%x + x
end subroutine
subroutine apply_B(AB,x)
implicit none
type(type_B),intent(inout) :: AB
integer,dimension(3),intent(in) :: x
AB%x = AB%x + x
end subroutine
end module
我可以简单地使用 type_AB 而不是在使用 test_mod 时指定 type_A 或 type_B。我知道我可以只指定两个对象,但除了等级之外它们基本上是相同的,所以有一种 composition/polymorphic 对象会很好,但我不想嵌入第二个派生对象输入一个。例如:
type type_AB
type(type_A) :: A
type(type_B) :: B
end type
因为它会使 class 文件更加混乱(引用 x 变成,例如 AB%A%x 而不是 AB%x,如果 AB 的类型是 type_AB)。如果这是唯一的方法,那么我想我可以这样做,但我想知道是否还有其他选择。此外,如果使用 type_A,则使用 composition/polymorphic 方法会增加需要在 type_B 中释放任何内容的烦恼,反之亦然..
我想其他人可能会以更好的方式提出这个问题,但当我查看示例时,大多数人似乎使用的是 f2003 标准,我对此有点陌生。非常感谢回答或改进问题的任何帮助,谢谢。
更新:
我尝试按照建议实现类型扩展,但这是我所能得到的。
module type_AB_mod
implicit none
private
public :: type_AB ! This is what I'd like to do...
public :: init
interface init; module procedure init_A; end interface
interface init; module procedure init_B; end interface
type type_AB
logical :: L
end type
type, extends(type_AB) :: type_A
integer :: x
end type
type, extends(type_AB) :: type_B
integer,dimension(3) :: x
end type
contains
subroutine init_A(AB,x)
implicit none
type(type_A),intent(inout) :: AB
integer,intent(in) :: x
AB%x = x
write(*,*) 'Init A'
end subroutine
subroutine init_B(AB,x)
implicit none
type(type_B),intent(inout) :: AB
integer,dimension(3),intent(in) :: x
AB%x = 2
write(*,*) 'Init B'
end subroutine
end module
program test
use type_AB_mod
implicit none
type(type_AB) :: AB
integer :: i
integer,dimension(3) :: j
call init(AB,i)
call init(AB,j)
end program
我收到两个错误,都是:
There is no specific subroutine for the generic 'init'
参考call init(AB,i)
和call init(AB,j)
更新 2:
我调整了示例以包含提供的答案:
module type_AB_mod
implicit none
private
public :: type_AB ! This is what I'd like to do...
public :: init
interface init; module procedure init_A; end interface
interface init; module procedure init_B; end interface
type type_AB
end type
type, extends(type_AB) :: type_A
integer :: x
end type
type, extends(type_AB) :: type_B
integer,dimension(3) :: x
end type
contains
subroutine init_A(AB,x)
implicit none
type(type_AB),allocatable,intent(inout) :: AB
integer,intent(in) :: x
allocate(AB, source=type_A(x=x))
write(*,*) 'Init A'
end subroutine
subroutine init_B(AB,x)
implicit none
type(type_AB),allocatable,intent(inout) :: AB
integer,dimension(3),intent(in) :: x
allocate(AB, source=type_B(x=x))
write(*,*) 'Init B'
end subroutine
end module
program test
use type_AB_mod
implicit none
class(type_AB),allocatable :: AB
integer :: i
integer,dimension(3) :: j
call init(AB,i)
deallocate(AB)
call init(AB,j)
deallocate(AB)
end program
但我仍然遇到编译器错误:
allocate(AB, source=type_B(x=x))
1 2
Error: Type of entity at (1) is type incompatible with source-expr at (2):
allocate(AB, source=type_A(x=x))
1 2
Error: Type of entity at (1) is type incompatible with source-expr at (2):
AB
是 type_AB
类型,您针对泛型 init
的特定过程是针对类型 type_A
和 type_B
。所以确实没有匹配。
你表示你希望了解这个的多态方法,所以一切都基于主程序中的type_AB
。
通过多态性,变量具有 声明的 和 动态的 类型。可以是 type_A
或 type_B
的变量将声明类型 type_AB
和当时适合的动态类型。
我们通过
将这样一个变量声明为type_AB
类型
class(type_AB), allocatable :: AB ! Or POINTER
我们可以通过
将其设置为动态类型type_A
allocate (type_A :: AB)
(和 type_B
比照)。
这导致通用分辨率。我们仍然在参数 x
的等级上消除歧义,但是两个特定过程都声明了类型 type_AB
(毕竟,您想根据另一个参数设置变量的动态类型,所以它不能用来消除歧义。
subroutine init_A(AB,x)
class(type_AB), allocatable, intent(out) :: AB
integer, intent(in) :: x
end subroutine
subroutine init_B(AB,x)
class(type_AB), allocatable, intent(out) :: AB
integer, intent(in) :: x(3)
end subroutine
这些都不含糊。剩下的就是在每个子例程中建立参数 AB
的动态类型和值。
为了清楚起见,我假设 type_AB
没有组件 L
。您可以稍后对此进行必要的修改。
在每个子程序中使用内部赋值,如
AB = type_A(x=x)
和
AB = type_B(x=x)
将处理动态类型和值。
但是,目前所有的编译器都不支持,因此您还有其他选择
allocate(AB, source=type_A(x=x))
或
allocate(type_A :: AB)
! ... setting the component AB%x is not trivial, but outside scope of answer
调用适当的特定子程序后,程序中 AB
的动态类型符合预期。
它使用上面 type_A
和 type_B
的构造函数,其中使用了删除组件 L
的简化。这是更一般情况下应该注意的地方。
最后,在我说 "either type_A
or type_B
" 的地方,声明类型为 type_AB
的变量也可以具有动态类型 type_AB
。将其设为抽象类型消除了这种可能性。
有没有办法使派生类型具有接口,以便为泛型派生类型调用特定的模块过程?我可能没有正确解释这一点,但这是我想做的简短示例代码:
module test_mod
implicit none
private
public :: type_AB ! This is what I'd like to do...
public :: init,apply,delete
interface type_AB ! This is what I'd like to do...
module type type_AB
end interface
interface init; module procedure init_A; end interface
interface init; module procedure init_B; end interface
interface apply; module procedure apply_A; end interface
interface apply; module procedure apply_B; end interface
type type_A
integer :: x
end type
type type_B
integer,dimension(3) :: x
end type
contains
subroutine init_A(AB,x)
implicit none
type(type_A),intent(inout) :: AB
integer,intent(in) :: x
AB%x = x
end subroutine
subroutine init_B(AB,x)
implicit none
type(type_B),intent(inout) :: AB
integer,dimension(3),intent(in) :: x
AB%x = 2
end subroutine
subroutine apply_A(AB,x)
implicit none
type(type_A),intent(inout) :: AB
integer,intent(in) :: x
AB%x = AB%x + x
end subroutine
subroutine apply_B(AB,x)
implicit none
type(type_B),intent(inout) :: AB
integer,dimension(3),intent(in) :: x
AB%x = AB%x + x
end subroutine
end module
我可以简单地使用 type_AB 而不是在使用 test_mod 时指定 type_A 或 type_B。我知道我可以只指定两个对象,但除了等级之外它们基本上是相同的,所以有一种 composition/polymorphic 对象会很好,但我不想嵌入第二个派生对象输入一个。例如:
type type_AB
type(type_A) :: A
type(type_B) :: B
end type
因为它会使 class 文件更加混乱(引用 x 变成,例如 AB%A%x 而不是 AB%x,如果 AB 的类型是 type_AB)。如果这是唯一的方法,那么我想我可以这样做,但我想知道是否还有其他选择。此外,如果使用 type_A,则使用 composition/polymorphic 方法会增加需要在 type_B 中释放任何内容的烦恼,反之亦然..
我想其他人可能会以更好的方式提出这个问题,但当我查看示例时,大多数人似乎使用的是 f2003 标准,我对此有点陌生。非常感谢回答或改进问题的任何帮助,谢谢。
更新:
我尝试按照建议实现类型扩展,但这是我所能得到的。
module type_AB_mod
implicit none
private
public :: type_AB ! This is what I'd like to do...
public :: init
interface init; module procedure init_A; end interface
interface init; module procedure init_B; end interface
type type_AB
logical :: L
end type
type, extends(type_AB) :: type_A
integer :: x
end type
type, extends(type_AB) :: type_B
integer,dimension(3) :: x
end type
contains
subroutine init_A(AB,x)
implicit none
type(type_A),intent(inout) :: AB
integer,intent(in) :: x
AB%x = x
write(*,*) 'Init A'
end subroutine
subroutine init_B(AB,x)
implicit none
type(type_B),intent(inout) :: AB
integer,dimension(3),intent(in) :: x
AB%x = 2
write(*,*) 'Init B'
end subroutine
end module
program test
use type_AB_mod
implicit none
type(type_AB) :: AB
integer :: i
integer,dimension(3) :: j
call init(AB,i)
call init(AB,j)
end program
我收到两个错误,都是:
There is no specific subroutine for the generic 'init'
参考call init(AB,i)
和call init(AB,j)
更新 2:
我调整了示例以包含提供的答案:
module type_AB_mod
implicit none
private
public :: type_AB ! This is what I'd like to do...
public :: init
interface init; module procedure init_A; end interface
interface init; module procedure init_B; end interface
type type_AB
end type
type, extends(type_AB) :: type_A
integer :: x
end type
type, extends(type_AB) :: type_B
integer,dimension(3) :: x
end type
contains
subroutine init_A(AB,x)
implicit none
type(type_AB),allocatable,intent(inout) :: AB
integer,intent(in) :: x
allocate(AB, source=type_A(x=x))
write(*,*) 'Init A'
end subroutine
subroutine init_B(AB,x)
implicit none
type(type_AB),allocatable,intent(inout) :: AB
integer,dimension(3),intent(in) :: x
allocate(AB, source=type_B(x=x))
write(*,*) 'Init B'
end subroutine
end module
program test
use type_AB_mod
implicit none
class(type_AB),allocatable :: AB
integer :: i
integer,dimension(3) :: j
call init(AB,i)
deallocate(AB)
call init(AB,j)
deallocate(AB)
end program
但我仍然遇到编译器错误:
allocate(AB, source=type_B(x=x))
1 2
Error: Type of entity at (1) is type incompatible with source-expr at (2):
allocate(AB, source=type_A(x=x))
1 2
Error: Type of entity at (1) is type incompatible with source-expr at (2):
AB
是 type_AB
类型,您针对泛型 init
的特定过程是针对类型 type_A
和 type_B
。所以确实没有匹配。
你表示你希望了解这个的多态方法,所以一切都基于主程序中的type_AB
。
通过多态性,变量具有 声明的 和 动态的 类型。可以是 type_A
或 type_B
的变量将声明类型 type_AB
和当时适合的动态类型。
我们通过
将这样一个变量声明为type_AB
类型
class(type_AB), allocatable :: AB ! Or POINTER
我们可以通过
将其设置为动态类型type_A
allocate (type_A :: AB)
(和 type_B
比照)。
这导致通用分辨率。我们仍然在参数 x
的等级上消除歧义,但是两个特定过程都声明了类型 type_AB
(毕竟,您想根据另一个参数设置变量的动态类型,所以它不能用来消除歧义。
subroutine init_A(AB,x)
class(type_AB), allocatable, intent(out) :: AB
integer, intent(in) :: x
end subroutine
subroutine init_B(AB,x)
class(type_AB), allocatable, intent(out) :: AB
integer, intent(in) :: x(3)
end subroutine
这些都不含糊。剩下的就是在每个子例程中建立参数 AB
的动态类型和值。
为了清楚起见,我假设 type_AB
没有组件 L
。您可以稍后对此进行必要的修改。
在每个子程序中使用内部赋值,如
AB = type_A(x=x)
和
AB = type_B(x=x)
将处理动态类型和值。
但是,目前所有的编译器都不支持,因此您还有其他选择
allocate(AB, source=type_A(x=x))
或
allocate(type_A :: AB)
! ... setting the component AB%x is not trivial, but outside scope of answer
调用适当的特定子程序后,程序中 AB
的动态类型符合预期。
它使用上面 type_A
和 type_B
的构造函数,其中使用了删除组件 L
的简化。这是更一般情况下应该注意的地方。
最后,在我说 "either type_A
or type_B
" 的地方,声明类型为 type_AB
的变量也可以具有动态类型 type_AB
。将其设为抽象类型消除了这种可能性。