func CopyFile(dstName, srcName string) (written int64, err os.Error) { src, err := os.Open(srcName, os.O_RDONLY, 0) if err != nil { return } dst, err := os.Open(dstName, os.O_WRONLY|os.O_CREATE, 0644) if err != nil { return } written, err = io.Copy(dst, src) dst.Close() src.Close() return }Le problème potentiel est que si le second appel à os.Open échoue, la fonction se terminera sans avoir fermé le fichier source. On peut y remédier en ajoutant un appel src.Close() avant la deuxième instruction de retour, mais si la fonction est bien plus complexe, il n'est pas dit que le développeur ait pensé à tous les cas de figure. L’instruction defer, nous permet de fermer les fichiers à tous les coups.
func CopyFile(dstName, srcName string) (written int64, err os.Error) { src, err := os.Open(srcName, os.O_RDONLY, 0) if err != nil { return } defer src.Close() dst, err := os.Open(dstName, os.O_WRONLY|os.O_CREATE, 0644) if err != nil { return } defer dst.Close() return io.Copy(dst, src) }Quel que soit le nombre d’instructions return dans la fonction, l’instruction defer fermera tous les fichiers à la fin d'exécution de la fonction. Le comportement du defer est prédictible :
func a() { i := 0 defer fmt.Println(i) i++ return }
func b() { for i := 0; i < 4; i++ { defer fmt.Print(i) } }
func c() (i int) { defer func() { i++ }() return 1 }
func paniquons() { defer func(s string) { fmt.Println("Ce message sera affiché en dernier") }() fmt.Println("Ce message sera affiché en premier") panic("Erreur") fmt.Println("Ce message ne sera pas affiché") }
package main import "fmt" func main() { f() fmt.Println("Retour normal de la fonction f.") } func f() { defer func() { if r := recover(); r != nil { fmt.Println("Recover appelé dans la fonction f : ", r) } }() fmt.Println("Appel de la fonction g.") g(0) fmt.Println("Retour normal de la fonction g.") } func g(i int) { if i > 3 { fmt.Println("Appel à panic") panic(fmt.Sprintf("%v", i)) } defer fmt.Println("Instruction retardée (defer) dans la fonction g : ", i) fmt.Println("Affichage dans la fonction g : ", i) g(i+1) }La fonction g reçoit en paramètre un entier i et panique si i est plus grand que 3, dans le cas contraire la fonction continue son exécution et s'appelle elle-même avec l’argument i+1.
Appel de la fonction g. Affichage dans la fonction g : 0 Affichage dans la fonction g : 1 Affichage dans la fonction g : 2 Affichage dans la fonction g : 3 Appel à panic Instruction retardée (defer) dans la fonction g : 3 Instruction retardée (defer) dans la fonction g : 2 Instruction retardée (defer) dans la fonction g : 1 Instruction retardée (defer) dans la fonction g : 0 Recover appelé dans la fonction f : 4 Retour normal de la fonction f.Si nous supprimons l'appel à defer dans la fonction f, il n'y a aura pas de récupération (avec recover) et le programme sera terminé plus tôt (sans revenir dans la fonction main de notre exemple). Le programme modifié affichera :
Appel de la fonction g. Affichage dans la fonction g : 0 Affichage dans la fonction g : 1 Affichage dans la fonction g : 2 Affichage dans la fonction g : 3 Appel à panic Instruction retardée (defer) dans la fonction g : 3 Instruction retardée (defer) dans la fonction g : 2 Instruction retardée (defer) dans la fonction g : 1 Instruction retardée (defer) dans la fonction g : 0 panic: 4 panic PC=0x2a9cd8 [... suite de l'affichage de la pile]
Une traduction du blog officiel de golang expliquant le mécanisme de la réflexion en Go. Lire »
Préconisations officielles pour la gestion des erreurs dans un programme golang. Cet article complète les explications sur panic, defer et recover Lire »
Traduction d'une partie des spécifications officielles du langage go, cet article explique comment go gère la mémoire. Lire »
Traduction d'un article du blog officiel expliquant comment échanger des données entre deux programmes golang grâce à un format natif Lire »
Traduction d'une partie des spécifications officielles du langage Go, cet article explique comment développer en Go. Lire »
Soyez le premier à commenter cet article
Tous les commentaires sont soumis à modération. Les balises HTML sont pour la plupart autorisées. Les liens contextuels et intéressants sont en follow.