在 SELECT TYPE 构造中访问扩展类型组件
Access extended type components in a SELECT TYPE construct
我正在尝试构建一个具有多态元素的可分配数组。一个最小的例子如下:
program PolyArray
implicit none
type basetype
integer :: ib
end type basetype
type, extends(basetype) :: exttype1
real :: r1
end type exttype1
type, extends(exttype1) :: exttype2
real :: r2
end type exttype2
type arraytype
class(basetype), allocatable :: comp
end type arraytype
type(arraytype), dimension(:), allocatable :: ary
integer :: N, i
N = 5
allocate (ary(N))
do i=1,N; if (mod(i,2)==0) then
allocate(exttype2::ary(i)%comp)
else if ( i==1) then
allocate(basetype::ary(i)%comp)
else
allocate(exttype1::ary(i)%comp)
end if; end do
do i=1,N; select type (this=>ary(i)%comp)
type is (basetype)
write(*,*) i, "is basetype"!, "%ib =", ary(i)%comp%ib
type is (exttype1)
write(*,*) i, "is exttype1"!, "%r1 =", ary(i)%comp%r1
type is (exttype2)
write(*,*) i, "is exttype2"!, "%r2 =", ary(i)%comp%r2
class default
write(*,*) i, "is unknown type !"
end select; end do
end program PolyArray
现在,上面的代码可以正常工作并打印出来(如预期的那样):
1 is basetype
2 is exttype2
3 is exttype1
4 is exttype2
5 is exttype1
但是,问题是,一旦我尝试通过取消注释每个 write(*,*)
行的注释部分来访问每个扩展类型的组件(例如 exttype1
的 r1
),我的编译器 (gfortran 7.5.0) 出现以下错误:
write(*,*) i, "is exttype1", "%r1 =", ary(i)%comp%r1
1
Error: 'r1' at (1) is not a member of the 'basetype' structure
poly.f90:40:60:
write(*,*) i, "is exttype2", "%r2 =", ary(i)%comp%r2
1
Error: 'r2' at (1) is not a member of the 'basetype' structure
我不明白为什么会产生这些错误,因为编译器显然可以识别扩展类型 exttype1
和 exttype2
。
访问 r1
和 r2
的正确方法是什么?
编辑:
通过在每个 write(*,*)
行中将 ary(i)%comp
更改为 this
,代码可以正常编译。这种修改有什么区别?这两个 NOT 如何等价?
在 select 类型结构中有
select type (this=>ary(i)%comp)
有两件事:select或和关联名称。 ary(i)%comp
是这里的 selector,this
是关联名称。
我们知道在这种情况下是关联名称 is required,因为 ary(i)%comp
不是名称。
然而,关联名称不仅仅是为了方便(就像它可能在关联构造中一样):它具有您在这里需要的基本要求 属性。在由类型守卫管理的块中,关联名称给出的变量具有声明类型守卫的类型; selector 保留声明的类型,因为它在构造之外。
有了所需的声明类型,我们就可以访问组件;仅仅拥有动态类型不会。
我正在尝试构建一个具有多态元素的可分配数组。一个最小的例子如下:
program PolyArray
implicit none
type basetype
integer :: ib
end type basetype
type, extends(basetype) :: exttype1
real :: r1
end type exttype1
type, extends(exttype1) :: exttype2
real :: r2
end type exttype2
type arraytype
class(basetype), allocatable :: comp
end type arraytype
type(arraytype), dimension(:), allocatable :: ary
integer :: N, i
N = 5
allocate (ary(N))
do i=1,N; if (mod(i,2)==0) then
allocate(exttype2::ary(i)%comp)
else if ( i==1) then
allocate(basetype::ary(i)%comp)
else
allocate(exttype1::ary(i)%comp)
end if; end do
do i=1,N; select type (this=>ary(i)%comp)
type is (basetype)
write(*,*) i, "is basetype"!, "%ib =", ary(i)%comp%ib
type is (exttype1)
write(*,*) i, "is exttype1"!, "%r1 =", ary(i)%comp%r1
type is (exttype2)
write(*,*) i, "is exttype2"!, "%r2 =", ary(i)%comp%r2
class default
write(*,*) i, "is unknown type !"
end select; end do
end program PolyArray
现在,上面的代码可以正常工作并打印出来(如预期的那样):
1 is basetype
2 is exttype2
3 is exttype1
4 is exttype2
5 is exttype1
但是,问题是,一旦我尝试通过取消注释每个 write(*,*)
行的注释部分来访问每个扩展类型的组件(例如 exttype1
的 r1
),我的编译器 (gfortran 7.5.0) 出现以下错误:
write(*,*) i, "is exttype1", "%r1 =", ary(i)%comp%r1
1
Error: 'r1' at (1) is not a member of the 'basetype' structure
poly.f90:40:60:
write(*,*) i, "is exttype2", "%r2 =", ary(i)%comp%r2
1
Error: 'r2' at (1) is not a member of the 'basetype' structure
我不明白为什么会产生这些错误,因为编译器显然可以识别扩展类型 exttype1
和 exttype2
。
访问 r1
和 r2
的正确方法是什么?
编辑:
通过在每个 write(*,*)
行中将 ary(i)%comp
更改为 this
,代码可以正常编译。这种修改有什么区别?这两个 NOT 如何等价?
在 select 类型结构中有
select type (this=>ary(i)%comp)
有两件事:select或和关联名称。 ary(i)%comp
是这里的 selector,this
是关联名称。
我们知道在这种情况下是关联名称 is required,因为 ary(i)%comp
不是名称。
然而,关联名称不仅仅是为了方便(就像它可能在关联构造中一样):它具有您在这里需要的基本要求 属性。在由类型守卫管理的块中,关联名称给出的变量具有声明类型守卫的类型; selector 保留声明的类型,因为它在构造之外。
有了所需的声明类型,我们就可以访问组件;仅仅拥有动态类型不会。