[Примечание: следующий подход использует много памяти для переменных-указателей, когда целевой массив огромен, поэтому он может быть не очень хорошим в зависимости от случаев ... Другие подходы могут быть намного лучше.]
Хотя невозможно указать производный тип непосредственно на массив примитивного типа, как насчет создания производного типа, состоящего из указателей, и установки их через функцию? Например ...
module testmod
implicit none
type view_t
integer, pointer :: nx, ny, vec(:)
endtype
contains
function makeview( arr ) result( v )
integer, target, intent(in) :: arr( : )
type(view_t) :: v
v % nx => arr( 1 )
v % ny => arr( 2 )
v % vec => arr( 3 : 4 )
endfunction
endmodule
program main
use testmod
implicit none
integer arr( 4 * 2 ), i, offset
type(view_t) :: v, views( 2 )
! We suppose that arr(:) consists of 2 blocks of data (each have 4 integers).
arr(:) = [( i, i = 1, size(arr) )] !! dummy data
print *, "arr = ", arr
! Create a view for the first block of arr(:).
v = makeview( arr( 1 : 4 ) )
print *, "v % {nx, ny} = ", v % nx, v % ny
print *, "v % vec = ", v % vec
! Create a set of views for all the blocks of arr(:).
do i = 1, 2
offset = (i - 1) * 4
views( i ) = makeview( arr( offset + 1 : offset + 4 ) )
enddo
arr( 7:8 ) = arr( 7:8 ) * 100 !! modify the original array
print *, "views( 1 ) % vec = ", views( 1 ) % vec
print *, "views( 2 ) % vec = ", views( 2 ) % vec
end
Результат (тест gfortran-8.f90)
arr = 1 2 3 4 5 6 7 8
v % {nx, ny} = 1 2
v % vec = 3 4
views( 1 ) % vec = 3 4
views( 2 ) % vec = 700 800
Дополнительные примечания:
- Мы также можем использовать
associate
, чтобы опустить объявление переменной представления (foo
), но в этом случае кажется, что мы не можем изменить foo % vec
и т. Д. (Возможно, потому что это выражение).
associate( foo => makeview( arr( 1:4 ) ) )
print *, foo % vec !! OK
! foo % vec = 100 !! error
endassociate
- Другим подходом может быть использование производного типа с компонентами без указателя и использование
c_f_pointer()
. Этот подход, кажется, работает, если все компоненты имеют примитивные типы по умолчанию (скажем, все целые числа по умолчанию), но в противном случае могут возникнуть проблемы (скажем, сочетание целочисленной и двойной точности) из-за заполнения (не очень уверен ...). Поэтому я думаю, что этот подход может быть полезен, но требует гораздо большей осторожности («небезопасно»).
type altview_t
sequence !(not necessary for uniform integers?)
integer :: nx, ny, vec(2)
endtype
type(altview_t), pointer :: altview( : )
call c_f_pointer( c_loc( arr(1) ), altview, [ size(arr) / (sizeof(altview)/4) ] )
print *, altview( k ) % vec