Ricerca…


Osservazioni

Funzioni e subroutine , insieme ai moduli , sono gli strumenti per suddividere un programma in unità. Ciò rende il programma più leggibile e gestibile. Ciascuna di queste unità può essere pensata come parte del codice che, idealmente, potrebbe essere compilato e testato separatamente. I programmi principali possono chiamare (o richiamare) tali sottoprogrammi (funzioni o subroutine) per eseguire un'attività.

Le funzioni e le subroutine sono diverse nel seguente senso:

  • Le funzioni restituiscono un singolo oggetto e - di solito - non alterano i valori dei suoi argomenti (cioè si comportano esattamente come una funzione matematica!);
  • Le subroutine di solito svolgono un compito più complicato e ordinariamente alterano i loro argomenti (se ne esiste qualcuno), così come altre variabili (ad es. Quelle dichiarate nel modulo che contiene la subroutine).

Le funzioni e le subroutine vanno sotto il nome di procedure . (Nel seguito useremo il verbo "call" come sinonimo di "invocare" anche se tecnicamente le procedure da call sono subroutine s, mentre le function s appaiono come lato destro del compito o nelle espressioni.)

Sintassi della funzione

Le funzioni possono essere scritte utilizzando diversi tipi di sintassi

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

Le funzioni restituiscono valori attraverso un risultato di funzione . A meno che l'istruzione della funzione non abbia una clausola di result , il result della funzione ha lo stesso nome della funzione. Con result il result della funzione è quello dato dal result . In ciascuno dei primi due esempi sopra il risultato della funzione è dato dal name ; nel terzo da res .

Il risultato della funzione deve essere definito durante l'esecuzione della funzione.

Le funzioni consentono di utilizzare alcuni prefissi speciali.

Funzione pura significa che questa funzione non ha effetti collaterali:

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

La funzione elementale è definita come operatore scalare, ma può essere invocata con array come argomento effettivo, nel qual caso la funzione verrà applicata a livello di elemento. A meno che non sia specificato il prefisso impure (introdotto in Fortran 2008), una funzione elementare è anche una funzione pura .

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

Dichiarazione di ritorno

L'istruzione return può essere utilizzata per uscire dalla funzione e dalla subroutine. A differenza di molti altri linguaggi di programmazione non è usato per impostare il valore di ritorno.

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

Questa funzione esegue un calcolo iterativo. Se il valore di f diventa negativo, la funzione restituisce il valore -1000.

Procedure ricorsive

In Fortran, le funzioni e le subroutine devono essere esplicitamente dichiarate come ricorsive , se devono chiamarsi di nuovo, direttamente o indirettamente. Pertanto, un'implementazione ricorsiva della serie di Fibonacci potrebbe essere simile a questa:

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

Un altro esempio può calcolare fattoriale:

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

Affinché una funzione faccia riferimento direttamente a se stessa, la sua definizione deve utilizzare il suffisso del result . Non è possibile che una funzione sia sia recursive che elemental .

L'intento di argomenti fittizi

L'attributo intent di un argomento fittizio in una subroutine o funzione dichiara l'uso previsto. La sintassi è uno dei due

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

Ad esempio, considera questa funzione:

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

  f = x*x
end function

L' intent(IN) specifica che l'argomento dummy (non puntatore) x non può mai essere definito o diventare indefinito in tutta la funzione o nella sua inizializzazione. Se un argomento fittizio puntatore ha l' intent(IN) attributo intent(IN) , questo vale per la sua associazione.

intent(OUT) per un argomento fittizio senza puntatore indica che l'argomento dummy diventa indefinito in caso di invocazione del sottoprogramma (ad eccezione di qualsiasi componente di un tipo derivato con inizializzazione predefinita) e deve essere impostato durante l'esecuzione. L'argomento effettivo passato come argomento fittizio deve essere definibile: il passaggio di una costante denominata o letterale o un'espressione non è consentito.

Analogamente a prima, se un argomento fittizio puntatore è intent(OUT) lo stato di associazione del puntatore diventa indefinito. L'argomento attuale qui deve essere una variabile puntatore.

intent(INOUT) specifica che l'argomento attuale è definibile ed è adatto sia per l'inoltro che per il ritorno dei dati dalla procedura.

Infine, un argomento fittizio può essere senza l'attributo intent . Tale argomento fittizio ha il suo uso limitato dall'argomento passato.

Ad esempio, considera

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

L'argomento i può avere alcun intent attributo che permette sia delle chiamate subroutine del programma principale.

Fare riferimento a una procedura

Affinché una funzione o una subroutine siano utili, è necessario fare riferimento. A una subroutine viene fatto riferimento in una dichiarazione di call

call sub(...)

e una funzione all'interno di un'espressione. A differenza di molti altri linguaggi, un'espressione non costituisce un'istruzione completa, quindi un riferimento alla funzione è spesso visto in un'istruzione di assegnazione o utilizzato in altro modo:

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

Esistono tre modi per designare una procedura a cui si fa riferimento:

  • come il nome di un puntatore di procedura o procedura
  • un componente di procedura di un oggetto di tipo derivato
  • un nome vincolante alla procedura di tipo binding

Il primo può essere visto come

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

subroutine sub()
end subroutine

e gli ultimi due come

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

Per una procedura con argomenti fittizi, il riferimento richiede argomenti effettivi corrispondenti, sebbene non sia possibile fornire argomenti fittizi facoltativi.

Considera la subroutine

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

Questo può essere fatto riferimento nei seguenti due modi

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

Questo è il cosiddetto riferimento posizionale : gli argomenti reali sono associati in base alla posizione negli elenchi degli argomenti. Qui, il dummy a è associato con 1 , b con 2 c (se specificato) con 3 .

In alternativa, è possibile utilizzare la referenziazione delle parole chiave quando la procedura ha un'interfaccia esplicita disponibile

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

che è lo stesso di sopra.

Tuttavia, con le parole chiave gli argomenti reali possono essere offerti in qualsiasi ordine

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

Possono essere utilizzati entrambi i riferimenti di posizione e parola chiave

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

purché venga fornita una parola chiave per ogni argomento che segue la prima apparizione di una parola chiave

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

Il valore del riferimento alla parola chiave è particolarmente pronunciato quando ci sono più argomenti fittizi facoltativi, come mostrato di seguito se nella definizione della subroutine sopra b erano anche facoltativi

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

Gli elenchi degli argomenti per le procedure con collegamento del testo oi puntatori alle procedure del componente con un argomento passato vengono considerati separatamente.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow