Поиск…


замечания

Функции и подпрограммы в сочетании с модулями являются инструментами для разбивки программы на единицы. Это делает программу более читаемой и управляемой. Каждый из этих блоков можно рассматривать как часть кода, который в идеале может быть скомпилирован и протестирован изолированно. Основная программа (ы) может вызывать (или вызывать) такие подпрограммы (функции или подпрограммы) для выполнения задачи.

Функции и подпрограммы различаются в следующем смысле:

  • Функции возвращают один объект и, как правило, не изменяют значения его аргументов (т. Е. Действуют как математическая функция!);
  • Подпрограммы обычно выполняют более сложную задачу, и они обычно изменяют свои аргументы (если они есть), а также другие переменные (например, те, которые указаны в модуле, который содержит подпрограмму).

Функции и подпрограммы коллективно идут под именем процедур . (В дальнейшем мы будем использовать глагол «вызов» как синоним «invoke», даже если технически процедуры, call ed, являются subroutine s, тогда как function s отображается как правая часть задания или в выражениях.)

Синтаксис функции

Функции могут быть записаны с использованием нескольких типов синтаксиса

function name()
  integer name
  name = 42
end function
integer function name()
  name = 42
end function
function name() result(res)
  integer res
  res = 42
end function

Функции возвращают значения через результат функции . Если оператор функции не имеет предложение result функции имеет то же имя, что и функция. В result функции получается из result . В каждом из первых двух примеров выше результат функции дается по name ; в третьем - res .

Результат функции должен быть определен во время выполнения функции.

Функции позволяют использовать некоторые специальные префиксы.

Чистая функция означает, что эта функция не имеет побочного эффекта:

pure real function square(x)
  real, intent(in) :: x
  square = x * x
end function

Элементная функция определяется как скалярный оператор, но она может быть вызвана с массивом как фактический аргумент, и в этом случае функция будет применяться по типу элемента. Если не указан impure префикс (введенный в Fortran 2008), элементарная функция также является чистой функцией.

elemental real function square(x)
  real, intent(in) :: x
  square = x * x
end function

Оператор возврата

Оператор return может использоваться для выхода из функции и подпрограммы. В отличие от многих других языков программирования он не используется для установки возвращаемого значения.

real function f(x)
  real, intent(in) :: x
  integer :: i

  f = x

  do i = 1, 10

    f = sqrt(f) - 1.0

    if (f < 0) then
      f = -1000.
      return
    end if

  end do
end function

Эта функция выполняет итеративное вычисление. Если значение f становится отрицательным, функция возвращает значение -1000.

Рекурсивные процедуры

В функциях Fortran и подпрограммах должны быть явно объявлены как рекурсивные , если они должны называть себя снова, прямо или косвенно. Таким образом, рекурсивная реализация серии Фибоначчи может выглядеть так:

recursive function fibonacci(term) result(fibo)
  integer, intent(in) :: term
  integer :: fibo

  if (term <= 1) then
    fibo = 1
  else
    fibo = fibonacci(term-1) + fibonacci(term-2)
  end if
  
end function fibonacci

Другим примером является возможность вычисления факториала:

recursive function factorial(n)  result(f)
  integer :: f
  integer, intent(in) :: n
  
  if(n == 0) then
    f = 1
  else
    f = n * f(n-1)
  end if
end function factorial

Для функции, непосредственно рекурсивно ссылающейся на себя, ее определение должно использовать суффикс result . Функция не может быть как recursive и elemental .

Предположение о ложных аргументах

Атрибут intent фиктивного аргумента в подпрограмме или функции объявляет о своем намеренном использовании. Синтаксис является либо одним из

intent(IN)
intent(OUT)
intent(INOUT)

Например, рассмотрим эту функцию:

real function f(x)
  real, intent(IN) :: x

  f = x*x
end function

intent(IN) указывает, что фиктивный аргумент x (не указатель) x никогда не может быть определен или не определен во всей функции или ее инициализации. Если у фиктивного аргумента указателя есть intent(IN) атрибута intent(IN) , это относится к его ассоциации.

intent(OUT) для аргумента фиктивного указателя без указателя означает, что фиктивный аргумент становится неопределенным при вызове подпрограммы (за исключением любых компонентов производного типа с инициализацией по умолчанию) и должен быть установлен во время выполнения. Фактический аргумент, переданный как фиктивный аргумент, должен быть определяемым: передача именованной или литеральной константы или выражения не допускается.

Аналогично предыдущему, если указатель фиктивный аргумент является intent(OUT) статус ассоциации указателя становится неопределенным. Фактический аргумент здесь должен быть переменной указателя.

intent(INOUT) указывает, что фактический аргумент является определяемым и подходит как для передачи, так и для возврата данных из процедуры.

Наконец, фиктивный аргумент может быть без атрибута intent . Такой фиктивный аргумент используется ограниченным фактическим аргументом.

Например, рассмотрим

integer :: i = 0
call sub(i, .TRUE.)
call sub(1, .FALSE.)

end

subroutine sub(i, update)
  integer i
  logical, intent(in) :: update
  if (update) i = i+1
end subroutine

Аргумент i может иметь никакого атрибута intent который разрешает оба вызова подпрограммы основной программы.

Ссылка на процедуру

Для полезности функции или подпрограммы она должна быть указана. Подпрограмма ссылается в заявлении о call

call sub(...)

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

x = func(...)
y = 1 + 2*func(...)

Существует три способа указания ссылки на процедуру:

  • как имя указателя процедуры или процедуры
  • компонент процедуры объекта производного типа
  • имя привязки процедуры привязки типа

Первое можно увидеть как

procedure(), pointer :: sub_ptr=>sub
call sub()   ! With no argument list the parentheses are optional
call sub_ptr()
end

subroutine sub()
end subroutine

и последние два

module mod
  type t
    procedure(sub), pointer, nopass :: sub_ptr=>sub
  contains
    procedure, nopass :: sub
  end type

contains

  subroutine sub()
  end subroutine

end module

use mod
type(t) x
call x%sub_ptr()   ! Procedure component
call x%sub()       ! Binding name

end

Для процедуры с фиктивными аргументами ссылка требует соответствующих фактических аргументов, хотя необязательные фиктивные аргументы могут не задаваться.

Рассмотрим подпрограмму

subroutine sub(a, b, c)
  integer a, b
  integer, optional :: c
end subroutine

На это могут ссылаться следующие два способа

call sub(1, 2, 3)   ! Passing to the optional dummy c
call sub(1, 2)      ! Not passing to the optional dummy c

Это так называемая позиционная ссылка: фактические аргументы связаны с позицией в списках аргументов. Здесь макет a связан с 1 , b с 2 и c (если указано) с 3 .

Альтернативно, привязка ключевых слов может использоваться, когда процедура имеет явный интерфейс, доступный

call sub(a=1, b=2, c=3)
call sub(a=1, b=2)

который является тем же самым, что и выше.

Однако с ключевыми словами фактические аргументы могут предлагаться в любом порядке

call sub(b=2, c=3, a=1)
call sub(b=2, a=1)

Позиционные и ссылки на ключевые слова могут использоваться как

call sub(1, c=3, b=2)

пока задано ключевое слово для каждого аргумента, следующего за первым появлением ключевого слова

call sub(b=2, 1, 3)  ! Not valid: all keywords must be specified

Значение ссылки на ключевые слова особенно заметно, когда имеется несколько необязательных аргументов фиктивного типа, как показано ниже, если в определении подпрограммы выше b также были необязательными

call sub(1, c=3)  ! Optional b is not passed

Списки аргументов для процедур с привязкой к типу или указатели процедур компонентов с переданным аргументом рассматриваются отдельно.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow