53 votes

Utilisation de différer dans Go

Quelle est l'utilisation de defer dans Go? La documentation de langue indique qu'il est exécuté au retour de la fonction environnante. Pourquoi ne pas simplement mettre le code à la fin d'une fonction donnée?

63voto

Grzegorz Żur Points 7263

Nous utilisons habituellement defer de la fermer ou de libérer des ressources.

Entouré d'une fonction exécute toutes les appels de fonction avant il retourne, même si elle s'affole. Si vous placez un appel de fonction à la fin de entouré d'une fonction, il est ignoré lorsque la panique qui se passe.

Par ailleurs, un différé d'appel de fonction peut gérer la panique par l'appel de la recover fonction intégrée. Cela ne peut être fait par simple appel de fonction à la fin d'une fonction.

Chaque différés appel est mis sur la pile, et exécutées dans l'ordre inverse lorsque l'environnement de la fonction se termine. L'inversion de l'ordre permet de libérer des ressources correctement.

L' defer déclaration doit être atteint pour une fonction à appeler.

Vous pouvez penser à elle comme une autre façon de mettre en oeuvre try-catch-finally blocs.

Clôture comme try-finally:

func main() {
    f, err := os.Create("file")
    if err != nil {
        panic("cannot create file")
    }
    defer f.Close()
    // no matter what happens here file will be closed
    // for sake of simplicity I skip checking close result
    fmt.Fprintf(f,"hello")
}

La fermeture et la panique manipulation comme l' try-catch-finally

func main() {
    defer func() {
        msg := recover()
        fmt.Println(msg)
    }()
    f, err := os.Create(".") // . is a current directory
    if err != nil {
        panic("cannot create file")
    }
    defer f.Close()
    // no matter what happens here file will be closed
    // for sake of simplicity I skip checking close result
    fmt.Fprintf(f,"hello")
}

L'avantage sur try-catch-finally est qu'il n'existe pas d'imbrication de blocs et variable étendues. Cela simplifie la structure de l'environnant de la fonction.

Tout comme, enfin, des blocs, des différés les appels de fonctions peuvent également modifier la valeur de retour si ils peuvent atteindre les données renvoyées.

func yes() (text string) {
    defer func() {
       text = "no"
    }()
    return "yes"
}

func main() {
    fmt.Println(yes())
}

11voto

Mayur Points 1571

Il y a déjà de bonnes réponses ici. Je voudrais mentionner un autre cas d'utilisation.

func BillCustomer(c *Customer) error {
    c.mutex.Lock()
    defer c.mutex.Unlock()

    if err := c.Bill(); err != nil {
        return err
    }

    if err := c.Notify(); err != nil {
        return err
    }

    // ... do more stuff ...

    return nil
}

L' defer dans cet exemple, assure que peu importe combien de BillCustomer rendements, l' mutex sera unlocked immédiatement avant l' BillCustomer de retour. C'est extrêmement utile, car sans defer vous devez penser à l' unlock le mutex dans chaque endroit que la fonction pourrait, éventuellement, return.

réf.

6voto

Ravi Points 965

Eh bien, il n'est pas toujours garanti que votre code peut atteindre la fin de la fonction (par exemple, une erreur ou une autre condition peut vous forcer à revenir bien avant la fin de la fonction). Le reporter instruction permet de s'assurer que, quelle que soit la fonction est assignée, il est exécuté à coup sûr même si la fonction panique ou le code renvoie le bien avant la fin de la fonction.

Le reporter déclaration permet également de maintenir le ménage dans le code de l'esp. dans les cas lorsqu'il y a plusieurs instructions return dans une fonction de l'esp. quand on a besoin de libérer des ressources avant de retourner (par exemple, imaginez que vous avez un appel ouvert pour accéder à une ressource au début de la fonction pour laquelle de proximité doit être appelée avant la fonction retourne pour éviter une fuite de ressources. Et dire votre fonction a plusieurs instructions return, peut-être pour différentes conditions, y compris la vérification des erreurs. Dans un tel cas, sans différer, vous le feriez normalement appel à proximité de cette ressource avant chaque instruction return). Le reporter instruction permet de s'assurer que la fonction que vous passez à elle est toujours appelée indépendamment de l'endroit où la fonction retourne une valeur, et donc vous permet d'économiser de extraenous travaux de ménage.

Aussi reporter peut être appelée plusieurs fois dans la même fonction. E. g.: Dans le cas où vous avez différentes ressources allouées par le biais de votre fonction qui a besoin d'être finalement libéré, avant de revenir, alors vous pouvez appeler différer pour chacun d'eux, après la répartition et ces fonctions sont exécutées dans l'ordre inverse de l'ordre dans lequel ils ont été appelé lorsque la fonction se termine.

3voto

Eugene Lisitsky Points 1119

Principaux avantages de l'utilisation de defer - , il sera appelé de toute façon, peu importe la façon dont la fonction sera de retour. Si une situation extraordinaire aurait lieu différés fonction sera appelée.

Donc ça donne de belles choses:

  1. Récupérer après l' panic. Cela permet oui réalisent try ... catch comportement.

  2. Ne pas oublier de nettoyer (fermer des fichiers, la mémoire libre, etc) avant la sortie normale. Vous pouvez ouvrir quelques ressources et vous devez la fermer avant de quitter. Mais la fonction peut avoir plusieurs points de sortie - donc, vous devez ajouter les libérant dans chaque point de retour. C'est très fastidieux de l'entretien. Ou vous pouvez mettre un seul reportés de l'instruction et des ressources sera libéré automatiquement.

1voto

Résumé:

Quand nous faisons de certaines opérations qui ont besoin de nettoyage, on peut "programmer" les opérations de nettoyage qui pourraient être exécutées lorsque la fonction retourne n'importe quel chemin qui se passe, notamment en raison de la panique.

Réponse détaillée:

  1. Les langages de programmation efforçons de fournir des constructions qui facilitent la plus simple et la moins sujette à erreur de développement. (E. g. pourquoi devrait Golang support de collecte des ordures quand nous pouvons nous libérer de la mémoire, de nous-mêmes)
  2. Une fonction peut renvoyer à de multiples points. L'utilisateur peut négliger de faire certaines opérations de nettoyage dans certains chemins
  3. Certaines opérations de nettoyage ne sont pas pertinents dans toutes les voies du retour
  4. Aussi, il est préférable de garder le code de nettoyage plus proche de l'original de l'opération qui avait besoin de la de nettoyage
  5. Quand nous faisons de certaines opérations qui ont besoin de nettoyage, on peut "programmer" les opérations de nettoyage qui pourraient être exécutées lorsque la fonction retourne n'importe quel chemin qui se passe.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X