Доступ к компонентам расширенного типа в конструкции SELECT TYPE

Я пытаюсь создать выделяемый массив с полиморфными элементами. Минимальный пример следующий:

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

Однако проблема заключается в том, что как только я пытаюсь получить доступ к компоненту каждого расширенного типа (например, r1 из exttype1), раскомментировав закомментированную часть каждой строки write(*,*), мой компилятор (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?

РЕДАКТИРОВАНИЕ: при замене ary(i)%comp на this в каждой write(*,*) строке код нормально компилируется. Чем отличается эта модификация? Как эти два НЕ эквивалентны?


person Xiasu Yang    schedule 25.03.2020    source источник
comment
Большое спасибо @francescalus! Изменение ary(i)%comp на this действительно решает мою проблему. Я думал, что оба будут работать, так как this — это просто «бирка имени» ary(i)%comp.   -  person Xiasu Yang    schedule 25.03.2020
comment
Первоначально я проголосовал за закрытие как опечатку, но теперь вы расширили путаницу вокруг this, я отказался и ответил. Возможно, вы можете добавить этот аспект к вашему вопросу.   -  person francescalus    schedule 25.03.2020


Ответы (1)


В конструкции типа select, где есть

select type (this=>ary(i)%comp)

есть две вещи: селектор и ассоциированное имя. Здесь ary(i)%comp — это селектор, а this — это ассоциированное имя.

Мы знаем, что в этом случае требуется ассоциированное имя , поскольку ary(i)%comp не является именем.

Однако ассоциированное имя предназначено не только для удобства (как это может быть в ассоциированной конструкции): оно имеет фундаментальное обязательное свойство, которое вам здесь нужно. В блоках, управляемых защитой типа, переменная, заданная ассоциативным именем, имеет объявленный тип защиты типа; селектор сохраняет объявленный тип, как и вне конструкции.

Наличие желаемого объявленного типа позволяет нам получить доступ к компонентам; просто наличие динамического типа не работает.

person francescalus    schedule 25.03.2020
comment
Еще раз спасибо, это очень хорошо объяснено! Я отредактирую свой вопрос, чтобы избежать дальнейшей путаницы - person Xiasu Yang; 25.03.2020