impossible de convertir les données (type interface {}) en chaîne de type: assertion de type requise

178

Je suis assez nouveau et je jouais avec ce package de notification .

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 une nouvelle ligne à Hello World!mais pas dans la fonction doitci-dessus, car ce serait assez trivial, mais par la handlersuite comme ceci 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 .

Ensuite, 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 j'étais censé faire? Mes erreurs de compilateur ont disparu, donc je suppose que c'est plutôt bien? Est-ce efficace? Devriez-vous le faire différemment?

Alfred
la source

Réponses:

292

Selon la spécification Go :

Pour une expression x de type interface et de 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 affirmiez que les données (type interface {}) ont la chaîne de type concrète. Si vous vous trompez, le programme paniquera lors 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 n'êtes pas sûr qu'il s'agisse d'une chaîne ou non, vous pouvez tester à l'aide de la syntaxe de retour.

str, ok := data.(string)

Si les données ne sont pas une chaîne, ok sera faux. Il est alors courant d'envelopper une telle instruction dans une instruction if comme ceci:

if str, ok := data.(string); ok {
    /* act on str */
} else {
    /* not string */
}
Stephen Weinberg
la source
29

Assertion de type

C'est ce qu'on appelle type assertionen golang, et c'est une pratique courante.

Voici l'explication d' un tour de go :

Une assertion de type permet d'accéder à 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 affecte la valeur T sous-jacente à la variable t.

Si je n'ai pas de T, la déclaration déclenchera une panique.

Pour tester 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 qui indique si l'assertion a réussi.

t, ok := i.(T)

Si i détient 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 produira.

REMARQUE: la valeur idoit être le type d'interface .

Pièges

Même si ic'est un type d'interface, ce []in'est pas un type d'interface. En conséquence, pour convertir []ien son type valeur, nous devons le faire individuellement:

// var items []i
for _, item := range items {
    value, ok := item.(T)
    dosomethingWith(value)
}

Performance

Quant aux performances, elles peuvent être plus lentes que l'accès direct à la valeur réelle, comme indiqué dans cette réponse stackoverflow .

cizix
la source
13
//an easy way:
str := fmt.Sprint(data)
Yuanbo
la source
21
Ajoutez une explication avec une réponse sur la façon dont cette réponse aide OP à résoudre le problème actuel
ρяσѕρєя K
3

Comme demandé par @ ρяσѕρєя, une explication peut être trouvée à https://golang.org/pkg/fmt/#Sprint . Des explications connexes peuvent être trouvées sur https://stackoverflow.com/a/44027953/12817546 et sur https://stackoverflow.com/a/42302709/12817546 . Voici la réponse complète de @ Yuanbo.

package main

import "fmt"

func main() {
    var data interface{} = 2
    str := fmt.Sprint(data)
    fmt.Println(str)
}
Tom J
la source
1
Je suppose que vous pouvez combiner les deux réponses en éditant simplement @ Yuanbo's - vous serez tous les deux crédités et additionner votre score respectif d'utilité 😉
Gwyneth Llewelyn