impossibile convertire i dati (digitare interfaccia {}) per digitare stringa: è necessario asserire il tipo


178

Sono abbastanza nuovo per andare e stavo giocando con questa notifica pacchetto di .

All'inizio avevo un codice simile al seguente:

func doit(w http.ResponseWriter, r *http.Request) {
    notify.Post("my_event", "Hello World!")
    fmt.Fprint(w, "+OK")
}

Volevo aggiungere newline a Hello World!ma non nella funzione doitsopra, perché sarebbe piuttosto banale, ma in handlerseguito come questo sotto:

func handler(w http.ResponseWriter, r *http.Request) {
    myEventChan := make(chan interface{})
    notify.Start("my_event", myEventChan)
    data := <-myEventChan
    fmt.Fprint(w, data + "\n")
}

Dopo go run:

$ go run lp.go 
# command-line-arguments
./lp.go:15: invalid operation: data + "\n" (mismatched types interface {} and string)

Dopo un po 'di Google ho trovato questa domanda su SO .

Quindi ho aggiornato il mio codice per:

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

È questo che dovevo fare? I miei errori del compilatore sono spariti, quindi immagino che sia abbastanza buono? È efficiente? Dovresti farlo diversamente?

Risposte:


292

Secondo le specifiche Go :

Per un'espressione x di tipo interfaccia e un tipo T, l'espressione primaria x. (T) afferma che x non è zero e che il valore memorizzato in x è di tipo T.

Una "asserzione di tipo" consente di dichiarare che un valore di interfaccia contiene un determinato tipo di calcestruzzo o che il suo tipo di calcestruzzo soddisfa un'altra interfaccia.

Nel tuo esempio, stavi affermando che i dati (tipo interfaccia {}) ha la stringa di tipo concreto. Se ti sbagli, il programma verrà preso dal panico in fase di esecuzione. Non devi preoccuparti dell'efficienza, il controllo richiede solo il confronto di due valori del puntatore.

Se non si era sicuri che fosse una stringa o no, è possibile eseguire il test utilizzando la sintassi di ritorno due.

str, ok := data.(string)

Se i dati non sono una stringa, ok sarà falso. È quindi comune racchiudere tale affermazione in un'istruzione if in questo modo:

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

29

Digita asserzione

Questo è noto come type assertionnel Golang ed è una pratica comune.

Ecco la spiegazione di un tour di go :

Un'asserzione di tipo fornisce l'accesso al valore concreto sottostante di un valore di interfaccia.

t := i.(T)

Questa affermazione afferma che il valore dell'interfaccia i contiene il tipo concreto T e assegna il valore T sottostante alla variabile t.

Se non detengo una T, la dichiarazione attiverà un panico.

Per verificare se un valore di interfaccia contiene un tipo specifico, un'asserzione di tipo può restituire due valori: il valore sottostante e un valore booleano che indica se l'asserzione ha avuto esito positivo.

t, ok := i.(T)

Se ho una T, allora t sarà il valore sottostante e ok sarà vero.

In caso contrario, ok sarà falso e t sarà il valore zero di tipo T e non si verifica alcun panico.

NOTA: valorei deve essere di tipo interfaccia .

insidie

Anche se iè un tipo di interfaccia, []inon è un tipo di interfaccia. Di conseguenza, al fine di convertire []ial suo tipo di valore, dobbiamo farlo individualmente:

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

Prestazione

Per quanto riguarda le prestazioni, può essere più lento dell'accesso diretto al valore effettivo, come mostrato in questa risposta dello stackoverflow .


13
//an easy way:
str := fmt.Sprint(data)

21
Aggiungi una spiegazione con la risposta su come questa risposta aiuta OP nel risolvere il problema attuale
ρяσѕρєя K

3

Come richiesto da @ ρяσѕρєя, è possibile trovare una spiegazione su https://golang.org/pkg/fmt/#Sprint . Ulteriori spiegazioni sono disponibili su https://stackoverflow.com/a/44027953/12817546 e su https://stackoverflow.com/a/42302709/12817546 . Ecco la risposta di @ Yuanbo per intero.

package main

import "fmt"

func main() {
    var data interface{} = 2
    str := fmt.Sprint(data)
    fmt.Println(str)
}

1
Immagino che potresti combinare entrambe le risposte semplicemente modificando @ Yuanbo's - entrambi ti verranno accreditati e sommerai il tuo rispettivo punteggio di 'utilità' 😉
Gwyneth Llewelyn
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.