Ricerca…


introduzione

defer spinge una chiamata di funzione in una lista. L'elenco delle chiamate salvate viene eseguito dopo il ritorno della funzione circostante. Defer è comunemente usato per semplificare le funzioni che eseguono varie azioni di pulizia.

Sintassi

  • differire someFunc (args)
  • defer func () {// code goes here} ()

Osservazioni

Il differimento funziona iniettando un nuovo stack frame (la funzione chiamata dopo la parola chiave defer ) nello stack di chiamate sotto la funzione attualmente in esecuzione. Ciò significa che il differimento è garantito per l'esecuzione fino a quando lo stack sarà svolto (se il tuo programma si blocca o ottiene un SIGKILL , il rinvio non verrà eseguito).

Defer Nozioni di base

Una dichiarazione di differimento in Go è semplicemente una chiamata di funzione contrassegnata per essere eseguita in un secondo momento. L'istruzione di defer è una chiamata di funzione ordinaria preceduta dal defer della parola chiave.

defer someFunction()

Una funzione differita viene eseguito una volta la funzione che contiene le defer restituisce istruzione. La chiamata effettiva alla funzione differita si verifica quando la funzione di chiusura:

  • esegue una dichiarazione di ritorno
  • cade alla fine
  • panico

Esempio:

func main() {
    fmt.Println("First main statement")
    defer logExit("main") // position of defer statement here does not matter
    fmt.Println("Last main statement")
}

func logExit(name string) {
    fmt.Printf("Function %s returned\n", name)
}

Produzione:

First main statement
Last main statement
Function main returned

Se una funzione ha più istruzioni posticipate, formano una pila. L'ultimo defer è il primo da eseguire dopo il ritorno della funzione di inclusione, seguito dalle successive chiamate al precedente defer in ordine (sotto l'esempio restituisce provocando un panico):

func main() {
    defer logNum(1)
    fmt.Println("First main statement")
    defer logNum(2)
    defer logNum(3)
    panic("panic occurred")
    fmt.Println("Last main statement") // not printed
    defer logNum(3) // not deferred since execution flow never reaches this line
}

func logNum(i int) {
    fmt.Printf("Num %d\n", i)
}

Produzione:

First main statement
Num 3
Num 2
Num 1
panic: panic occurred

goroutine 1 [running]:
....

Si noti che le funzioni posticipate hanno i loro argomenti valutati al momento defer :

func main() {
    i := 1
    defer logNum(i) // deferred function call: logNum(1)
    fmt.Println("First main statement")
    i++
    defer logNum(i) // deferred function call: logNum(2)
    defer logNum(i*i) // deferred function call: logNum(4)
    return // explicit return
}

func logNum(i int) {
    fmt.Printf("Num %d\n", i)
}

Produzione:

First main statement
Num 4
Num 2
Num 1

Se una funzione ha denominato valori di ritorno, una funzione anonima differita all'interno di quella funzione può accedere e aggiornare il valore restituito anche dopo che la funzione è ritornata:

func main() {
    fmt.Println(plusOne(1)) // 2
    return
}

func plusOne(i int) (result int) { // overkill! only for demonstration
    defer func() {result += 1}() // anonymous function must be called by adding ()

    // i is returned as result, which is updated by deferred function above
    // after execution of below return
    return i
}

Infine, una dichiarazione di defer viene generalmente utilizzata operazioni che spesso si verificano insieme. Per esempio:

  • aprire e chiudere un file
  • connettersi e disconnettersi
  • bloccare e sbloccare un mutex
  • segna un waitgroup come fatto ( defer wg.Done() )

Questo utilizzo garantisce il corretto rilascio delle risorse di sistema indipendentemente dal flusso di esecuzione.

resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close() // Body will always get closed

Chiamate a funzioni differite

Le chiamate a funzioni differite hanno uno scopo simile a cose come blocchi finally in linguaggi come Java: assicurano che alcune funzioni vengano eseguite quando la funzione esterna ritorna, indipendentemente dal fatto che si sia verificato un errore o che sia stata rilasciata una dichiarazione di ritorno in caso di più resi. Questo è utile per ripulire le risorse che devono essere chiuse come connessioni di rete o puntatori di file. La parola chiave defer indica una chiamata a una funzione differita, analogamente alla parola chiave go avvia una nuova goroutine. Come una chiamata go , gli argomenti delle funzioni vengono valutati immediatamente, ma a differenza di una chiamata go , le funzioni posticipate non vengono eseguite contemporaneamente.

func MyFunc() {
    conn := GetConnection()    // Some kind of connection that must be closed.
    defer conn.Close()        // Will be executed when MyFunc returns, regardless of how.
    // Do some things...
    if someCondition {
        return                // conn.Close() will be called
    }
    // Do more things
}// Implicit return - conn.Close() will still be called

Nota l'uso di conn.Close() invece di conn.Close : non stai passando solo una funzione, stai rimandando una chiamata a una funzione completa, inclusi i suoi argomenti. Le chiamate a funzioni multiple possono essere rinviate nella stessa funzione esterna e ciascuna verrà eseguita una volta nell'ordine inverso. Puoi anche differire le chiusure - non dimenticare i paren!

defer func(){
    // Do some cleanup
}()


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