Что касается объекта, я изо всех сил пытаюсь понять логику функций, возвращающих выделяемые массивы. Мне нравится эта конструкция из-за ее ясности по сравнению с подпрограммами, а также из-за того, что чистые функции на фортране — отличный способ написать чистый, функциональный программный код.
Предположим, мне нужно написать простую функцию, возвращающую массив индексов с произвольными границами, как в этой программе:
program test_allocatable_functionReturn
implicit none
integer, allocatable :: fun(:),sub(:),noa(:)
integer, parameter :: low = -4
integer, parameter :: hi = 3
call testsub(sub,low,hi)
fun = testfun(low,hi)
noa = testfun_noalloc(low,hi)
print '(4(a,i3),a)', 'testsub: lbound=',lbound(sub),'(expected = ',low,'), ubound=',ubound(sub),'(expected = ',hi,')'
print '(4(a,i3),a)', 'testfun: lbound=',lbound(fun),'(expected = ',low,'), ubound=',ubound(fun),'(expected = ',hi,')'
print '(4(a,i3),a)', 'no alloc: lbound=',lbound(noa),'(expected = ',low,'), ubound=',ubound(noa),'(expected = ',hi,')'
contains
pure function testfun_noalloc(low,hi) result(array)
integer, intent(in) :: low,hi
integer :: array(low:hi)
integer :: i
forall(i=low:hi) array(i) = i
end function testfun_noalloc
pure function testfun(low,hi) result(array)
integer, allocatable :: array(:)
integer, intent(in) :: low,hi
integer :: i
allocate(array(low:hi))
forall(i=low:hi) array(i) = i
end function testfun
pure subroutine testsub(array,low,hi)
integer, intent(out), allocatable :: array(:)
integer, intent(in) :: low,hi
integer :: i
allocate(array(low:hi))
forall(i=low:hi) array(i) = i
end subroutine testsub
end program
Я реализовал это тремя способами:
- функция, возвращающая размещаемый массив (
testfun
) - подпрограмма (
testsub
) - функция, возвращающая статический массив (
testfun_noalloc
)
Подпрограмма работает с возвращаемым массивом и правильно распределяет его. В примере должен быть возвращен массив размером (-4:3)
. Функция в любой реализации возвращает массив размером (1:hi-low+1)
:
testsub: lbound= -4(expected = -4), ubound= 3(expected = 3)
testfun: lbound= 1(expected = -4), ubound= 8(expected = 3)
no alloc: lbound= 1(expected = -4), ubound= 8(expected = 3)
Почему это происходит? Я понимаю, что fortran может перераспределить массив при присвоении возвращаемого значения функции моему массиву LHS, но даже в этом случае, почему он не выделяется с правильными границами? Я понимаю, что такое может произойти при передаче статического массива в выделяемый массив с перераспределением левой части в стиле f2003, но при использовании в качестве входного размещаемого массива я ожидал, что информация о границах будет сохранена. Я что-то упустил здесь? Кстати, этот пример был скомпилирован с помощью gfortran 9.2.0.
Спасибо, Федерико.