Je suis assez nouveau pour y aller et je jouais avec ce paquet notify .
Au début, j'avais un code qui ressemblait à ceci:
func doit(w http.ResponseWriter, r *http.Request) {
notify.Post("my_event", "Hello World!")
fmt.Fprint(w, "+OK")
}
Je voulais ajouter newline à Hello World!
mais pas dans la fonction doit
ci-dessus, car ce serait assez trivial, mais dans la handler
comme ci-dessous:
func handler(w http.ResponseWriter, r *http.Request) {
myEventChan := make(chan interface{})
notify.Start("my_event", myEventChan)
data := <-myEventChan
fmt.Fprint(w, data + "\n")
}
Après go run
:
$ go run lp.go
# command-line-arguments
./lp.go:15: invalid operation: data + "\n" (mismatched types interface {} and string)
Après un peu de recherche sur Google, j'ai trouvé cette question sur SO .
Puis j'ai mis à jour mon code pour:
func handler(w http.ResponseWriter, r *http.Request) {
myEventChan := make(chan interface{})
notify.Start("my_event", myEventChan)
data := <-myEventChan
s:= data.(string) + "\n"
fmt.Fprint(w, s)
}
Est-ce ce que je devais faire? Mes erreurs de compilateur ont disparu, alors je suppose que c'est plutôt bon? Est-ce efficace? Devriez-vous le faire différemment?
Selon le Go spécification :
Pour une expression x de type interface et un type T, l'expression primaire x. (T) affirme que x n'est pas nul et que la valeur stockée dans x est de type T.
Une "assertion de type" vous permet de déclarer qu'une valeur d'interface contient un certain type concret ou que son type concret satisfait une autre interface.
Dans votre exemple, vous déclariez que les données (type interface {}) correspondent à la chaîne de type concret. Si vous vous trompez, le programme panique au moment de l'exécution. Vous n'avez pas à vous soucier de l'efficacité, la vérification nécessite simplement de comparer deux valeurs de pointeur.
Si vous ne saviez pas s'il s'agissait d'une chaîne ou non, vous pouvez tester à l'aide de la syntaxe de retour.
str, ok := data.(string)
Si data n'est pas une chaîne, ok sera false. Il est alors courant d’envelopper une telle déclaration dans une instruction if comme ceci:
if str, ok := data.(string); ok {
/* act on str */
} else {
/* not string */
}
Ceci est appelé type assertion
in golang, et c'est une pratique courante.
Voici l'explication de n tour de go :
Une assertion de type donne accès à la valeur concrète sous-jacente d'une valeur d'interface.
t := i.(T)
Cette déclaration affirme que la valeur d'interface i contient le type concret T et assigne la valeur T sous-jacente à la variable t.
Si je ne suis pas titulaire d'un T, la déclaration déclenchera une panique.
Pour vérifier si une valeur d'interface contient un type spécifique, une assertion de type peut renvoyer deux valeurs: la valeur sous-jacente et une valeur booléenne indiquant si l'assertion a réussi.
t, ok := i.(T)
Si i est titulaire d'un T, alors t sera la valeur sous-jacente et ok sera vrai.
Sinon, ok sera faux et t sera la valeur zéro du type T, et aucune panique ne se produit.
NOTE: la valeur i
doit être du type d'interface .
Même si i
est un type d'interface, []i
n'est pas un type d'interface. En conséquence, pour convertir []i
en son type de valeur, nous devons le faire individuellement:
// var items []i
for _, item := range items {
value, ok := item.(T)
dosomethingWith(value)
}
En ce qui concerne les performances, il peut être plus lent que l’accès direct à la valeur réelle, comme indiqué dans cette réponse stackoverflow .
//an easy way:
str := fmt.Sprint(data)