在 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(*,*) 行的注释部分来访问每个扩展类型的组件(例如 exttype1r1),我的编译器 (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

我不明白为什么会产生这些错误,因为编译器显然可以识别扩展类型 exttype1exttype2。 访问 r1r2 的正确方法是什么?

编辑: 通过在每个 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 保留声明的类型,因为它在构造之外。

有了所需的声明类型,我们就可以访问组件;仅仅拥有动态类型不会。