Массив производного типа: выберите запись - PullRequest
3 голосов
/ 24 марта 2012

В настоящее время в моем коде у меня есть 2D-массив

integer, allocatable :: elements(:,:)

и определим некоторые константы

integer, parameter :: TYP = 1
integer, parameter :: WIDTH = 2
integer, parameter :: HEIGHT = 3
! ...
integer, parameter :: NUM_ENTRIES = 10

и выделите что-то вроде

allocate(elements(NUM_ENTRIES,10000))

чтобы получить доступ к таким элементам, как

write(*,*) elements(WIDTH,100) ! gives the width of the 100th element

Теперь я хотел бы иметь не только целое число, но и смесь типов для каждого элемента. Поэтому я определяю производный тип

type Element
    logical active
    integer type
    real width
    ! etc
end type

и использовать массив элементов

type(Element), allocatable :: elements(:)

С версией 2d-массива я мог бы вызвать подпрограмму, сообщающую, какую запись использовать. Э.Г.

subroutine find_average(entry, avg)
    integer, intent(in) :: entry   
    real, intent(out) :: avg
    integer i, 
    real s

    s = 0
    do i = lbound(elements,1), ubound(elements,1)
        if (elements(TYP,i) .gt. 0) s = s + elements(entry,i)
    end do
    avg = s/(ubound(elements,1)-lbound(elements,1))
end subroutine       

Так что я мог бы call find_average(HEIGHT) найти среднюю высоту или передать WIDTH, чтобы получить среднюю ширину. (А мои подпрограммы делают более сложные вещи, чем нахождение средней высоты или ширины, это всего лишь пример.)

Вопрос: Как я могу использовать разные типы (как с производным типом), но также повторно использовать свои функции для работы с разными записями (как в подпрограмме примера)?

1 Ответ

4 голосов
/ 24 марта 2012

В случае массива вместо передачи массива аргументов и индекса i можно передать массив аргументов с одним аргументом (i).Когда вы переключаетесь на использование производного типа, аналогичным образом вы можете передать элемент variable_of_type% вместо того, чтобы передавать весь variable_of_type и каким-то образом указывать процедуре, над каким подэлементом он должен работать.Если код должен быть различным для разных типов элементов (например, логический, целочисленный, вещественный), то вы можете написать конкретные процедуры для каждого из них, но затем вызывать их с общим именем через общий интерфейсный блок.Компилятор должен уметь различать процедуры общего интерфейсного блока по некоторой характеристике аргументов, здесь их тип.Пример кода, в котором отличительной характеристикой является ранг массива, см. Как написать оболочку для 'allocate'

EDIT: пример кода.это делает то, что вы хотите?

module my_subs

   implicit none

   interface my_sum
      module procedure sum_real, sum_int
   end interface my_sum

contains

subroutine sum_real (array, tot)
   real, dimension(:), intent (in) :: array
   real, intent (out) :: tot
   integer :: i

   tot = 1.0
   do i=1, size (array)
      tot = tot * array (i)
   end do
end subroutine sum_real

subroutine sum_int (array, tot)
   integer, dimension(:), intent (in) :: array
   integer, intent (out) :: tot
   integer :: i

   tot = 0
   do i=1, size (array)
      tot = tot + array (i)
   end do
end subroutine sum_int

end module my_subs


program test_dt

use my_subs

implicit none

type my_type
   integer weight
   real length
end type my_type

type (my_type), dimension (:), allocatable :: people
type (my_type) :: answer

allocate (people (2))

people (1) % weight = 1
people (1) % length = 1.0
people (2) % weight = 2
people (2) % length = 2.0

call my_sum ( people (:) % weight, answer % weight )
write (*, *)  answer % weight

call my_sum ( people (:) % length, answer % length )
write (*, *)  answer % length

end program test_dt
...