Szukaj…


Uwagi

Funkcje i podprogramy w połączeniu z modułami są narzędziami do podziału programu na jednostki. Dzięki temu program jest bardziej czytelny i zarządzalny. Każda z tych jednostek może być uważana za część kodu, który idealnie można skompilować i przetestować osobno. Program główny może wywoływać (lub wywoływać) takie podprogramy (funkcje lub podprogramy) w celu wykonania zadania.

Funkcje i podprogramy różnią się w następującym znaczeniu:

  • Funkcje zwracają pojedynczy obiekt i - zwykle - nie zmieniają wartości jego argumentów (tj. Działają one jak funkcja matematyczna!);
  • Podprogramy zwykle wykonują bardziej skomplikowane zadanie i zwykle zmieniają swoje argumenty (jeśli takie istnieją), a także inne zmienne (np. Zadeklarowane w module zawierającym podprogram).

Funkcje i podprogramy łącznie są nazywane procedurami . (W dalszej części użyjemy czasownika „call” jako synonimu „invoke”, nawet jeśli technicznie procedury do callsubroutine , podczas gdy function pojawiają się jako prawa strona przypisania lub wyrażeń.)

Składnia funkcji

Funkcje można pisać przy użyciu kilku rodzajów składni

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

Funkcje zwracają wartości poprzez wynik funkcji . O ile instrukcja funkcji nie zawiera klauzuli wynikowej, result funkcji ma taką samą nazwę jak funkcja. Z result funkcji jest wynikiem podanym przez result . W każdym z dwóch pierwszych przykładów powyżej wynik funkcji podany jest po name ; w trzecim przez res .

Wynik funkcji musi zostać zdefiniowany podczas wykonywania funkcji.

Funkcje pozwalają używać specjalnych prefiksów.

Czysta funkcja oznacza, że ta funkcja nie ma skutków ubocznych:

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

Funkcja elementarna jest zdefiniowana jako operator skalarny, ale można ją wywołać za pomocą tablicy jako argumentu rzeczywistego, w którym to przypadku funkcja zostanie zastosowana elementarnie. O ile nie podano impure prefiksu (wprowadzonego w Fortran 2008), funkcja elementarna jest również funkcją czystą .

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

Oświadczenie zwrotne

Za pomocą instrukcji return można wyjść z funkcji i podprogramu. W przeciwieństwie do wielu innych języków programowania nie jest on używany do ustawiania wartości zwracanej.

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

Ta funkcja wykonuje obliczenia iteracyjne. Jeśli wartość f staje się ujemna, funkcja zwraca wartość -1000.

Procedury rekurencyjne

W Fortranie funkcje i podprogramy muszą być jawnie zadeklarowane jako rekurencyjne , jeśli mają się ponownie wywoływać, bezpośrednio lub pośrednio. Zatem rekurencyjna implementacja serii Fibonacciego może wyglądać następująco:

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

Dozwolony jest inny przykład do obliczenia silni:

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

Aby funkcja odwoływała się bezpośrednio do siebie rekurencyjnie, jej definicja musi używać sufiksu result . Funkcja nie może być zarówno recursive jak i elemental .

The Intent of Dummy Arguments

Atrybut intent fałszywego argumentu w podprogramie lub funkcji deklaruje jego zamierzone użycie. Składnia jest albo jedna z

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

Rozważmy na przykład tę funkcję:

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

  f = x*x
end function

intent(IN) określa, że (pozointerowy) fikcyjny argument x nigdy nie może zostać zdefiniowany lub stać się niezdefiniowany podczas funkcji lub jej inicjalizacji. Jeśli fikcyjny wskaźnik wskaźnika ma intent(IN) atrybutu intent(IN) , dotyczy to jego powiązania.

intent(OUT) dla fikcyjnego argumentu niepointerowego oznacza, że fikcyjny argument staje się niezdefiniowany po wywołaniu podprogramu (z wyjątkiem jakichkolwiek komponentów typu pochodnego z domyślną inicjalizacją) i należy go ustawić podczas wykonywania. Rzeczywisty argument przekazany jako fikcyjny argument musi być możliwy do zdefiniowania: przekazywanie stałej nazwanej lub dosłownej lub wyrażenia jest niedozwolone.

Podobnie jak poprzednio, jeśli intent(OUT) jest argument pozorny wskaźnika intent(OUT) status powiązania wskaźnika staje się niezdefiniowany. Rzeczywistym argumentem tutaj musi być zmienna wskaźnikowa.

intent(INOUT) określa, że rzeczywisty argument jest definiowalny i nadaje się zarówno do przekazywania, jak i zwracania danych z procedury.

Wreszcie, fikcyjny argument może być pozbawiony atrybutu intent . Taki fikcyjny argument ma zastosowanie ograniczone przez przekazany argument.

Rozważmy na przykład

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

Argument i może mieć atrybutu intent który zezwala na oba wywołania podprogramu programu głównego.

Odwołanie do procedury

Aby funkcja lub podprogram był użyteczny, należy się do niego odwoływać. Do podprogramu odwołuje się instrukcja call

call sub(...)

i funkcja w wyrażeniu. W przeciwieństwie do wielu innych języków, wyrażenie nie tworzy pełnej instrukcji, więc odwołanie do funkcji jest często widziane w instrukcji przypisania lub używane w inny sposób:

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

Istnieją trzy sposoby wyznaczenia odwoływanej procedury:

  • jako nazwa procedury lub wskaźnik procedury
  • komponent procedury obiektu typu pochodnego
  • nazwa powiązania procedury powiązanej z typem

Pierwszy można uznać za

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

subroutine sub()
end subroutine

a dwa ostatnie jako

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

W przypadku procedury z fałszywymi argumentami odwołanie wymaga odpowiednich rzeczywistych argumentów, chociaż opcjonalne argumenty fałszywe mogą nie zostać podane.

Rozważ podprogram

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

Można się do tego odwołać na dwa następujące sposoby

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

Jest to tak zwane odwołanie pozycyjne : rzeczywiste argumenty są powiązane na podstawie pozycji na listach argumentów. W tym przypadku manekin a jest powiązany z 1 , b z 2 a c (jeśli określono) z 3 .

Alternatywnie można użyć odwołania do słów kluczowych , gdy procedura ma dostępny jawny interfejs

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

który jest taki sam jak powyżej.

Jednak w przypadku słów kluczowych rzeczywiste argumenty mogą być oferowane w dowolnej kolejności

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

Można stosować zarówno odwołania do pozycji, jak i do słów kluczowych

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

o ile słowo kluczowe jest podane dla każdego argumentu następującego po pierwszym wystąpieniu słowa kluczowego

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

Wartość odwoływania się do słów kluczowych jest szczególnie wyraźna, gdy istnieje wiele opcjonalnych fałszywych argumentów, jak pokazano poniżej, jeśli w definicji podprogramu powyżej b były również opcjonalne

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

Listy argumentów dla procedur związanych z typem lub wskaźników procedur składowych z przekazanym argumentem są rozpatrywane osobno.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow