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?
Réponses
Trop de publicités?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())
}
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.
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.
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:
Récupérer après l'
panic
. Cela permet oui réalisenttry ... catch
comportement.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.
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:
- 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)
- Une fonction peut renvoyer à de multiples points. L'utilisateur peut négliger de faire certaines opérations de nettoyage dans certains chemins
- Certaines opérations de nettoyage ne sont pas pertinents dans toutes les voies du retour
- 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
- 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.