2017-10-11 1 views
1

Consultez le code suivant:Le report d'une assignation de zone à une condition de concurrence?

type foo struct { 
    bar string 
} 

func f() *foo { 
    ret := &foo{"before"} 
    defer func() { ret.bar = "after" }() 
    return ret 
} 

func main() { 
    fmt.Println(f()) // prints "&{after}" 
} 

La motivation est d'avoir à retourner une struct, mais quelques-uns des champs doivent être réglés que avant de retourner (par exemple un horodatage lorsque la fonction terminée).

Est-ce que le report de l'affectation de zone est une condition de concurrence? Est-ce idiomatique? Y a-t-il un meilleur moyen?

+5

Il n'y a rien ici en même temps, donc il ne peut y avoir course. – JimB

+0

@JimB merci. Est-il idiomatique ou existe-t-il une meilleure façon de le faire? – ale64bit

+3

Pour faire quoi? Quel est l'objectif? Il n'y a pas de raison pour que vous ne puissiez pas définir une variable dans une instruction de report, mais si elle est idiomatique dépend de votre objectif. – Flimzy

Répondre

1

Le principal avantage de l'utilisation de l'instruction defer par rapport à l'invocation d'un élément avant le retour d'une fonction ou d'une routine est que defer exécutera l'instruction même si une alarme survient avant le retour.

Ainsi, il est couramment utilisé pour nettoyer les ressources (telles que la fermeture d'un fichier ou d'une connexion réseau) plutôt que de définir l'état.

La fonction ci-dessous ne sera pas imprimer ou retourner « bonjour »

func f() string { 
     panic("omg") 
     fmt.Println("hello") 
     return "hello" 
} 

Ce code sera imprimé mais ne reviendra pas « bonjour »

func f() string { 
     defer fmt.Println("ello") 
     panic("omg") 
     return "hello" 
} 

Pour répondre à votre question: Non, il a gagné ne se traduira pas par une course. En dehors de la différence ci-dessus, cela équivaut à appeler quelque chose avant l'instruction return.

1

Vous mentionnez l'horodatage lorsqu'une fonction est terminée. Dans ce cas, vous pouvez utiliser defer comme ceci:

package main 

import (
    "fmt" 
    "time" 
) 

func main() { 
    foo() 
} 

func foo() { 
    defer trace("foo")() 
    time.Sleep(1 * time.Second) 
} 

func trace(fn string) func() { 
    start := time.Now() 
    return func() { 
     layout := "15:04:05.000" 
     end := time.Now() 
     fmt.Printf("%s start at %s, end at %s, total %s", fn, start.Format(layout), end.Format(layout), end.Sub(start)) 
    } 
} 

Sortie: foo start at 23:00:00.000, end at 23:00:01.000, total 1s