Go Différer les bases


Exemple

Une déclaration différée dans Go est simplement un appel de fonction marqué pour être exécuté ultérieurement. L'instruction de report est un appel de fonction ordinaire préfixé par le mot-clé defer .

defer someFunction()

Une fonction différée est exécutée une fois que la fonction qui contient la déclaration de defer est retournée. L'appel réel à la fonction différée se produit lorsque la fonction englobante:

  • exécute une déclaration de retour
  • tombe la fin
  • panique

Exemple:

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)
}

Sortie:

First main statement
Last main statement
Function main returned

Si une fonction comporte plusieurs instructions différées, elles forment une pile. Le dernier defer est le premier à s'exécuter après le retour de la fonction englobante, suivi des appels suivants au defer précédent dans l'ordre (l'exemple ci-dessous renvoie en provoquant une panique):

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)
}

Sortie:

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

goroutine 1 [running]:
....

Notez que les fonctions différées ont leurs arguments évalués au moment defer exécute:

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)
}

Sortie:

First main statement
Num 4
Num 2
Num 1

Si une fonction a des valeurs de retour nommées, une fonction anonyme différée au sein de cette fonction peut accéder à la valeur renvoyée et la mettre à jour même après le retour de la fonction:

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
}

Enfin, une déclaration defer est généralement utilisée pour des opérations qui se produisent souvent ensemble. Par exemple:

  • ouvrir et fermer un fichier
  • connecter et déconnecter
  • verrouiller et déverrouiller un mutex
  • marquer un groupe d’attente comme fait ( defer wg.Done() )

Cette utilisation garantit une libération correcte des ressources du système, quel que soit le flux d'exécution.

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