web-dev-qa-db-fra.com

ne peut pas convertir les données (type interface {}) en chaînes de caractères: besoin d'une assertion de type

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?

155
Alfred

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 */
}
273
Stephen Weinberg

Assertion de type

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 .

Les pièges

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)
}

Performance

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 .

20
cizixs
//an easy way:
str := fmt.Sprint(data)
10
Yuanbo