não é possível converter dados (digite interface {}) para digitar string: need type assertion

176

Eu sou muito novo para ir e eu estava jogando com este pacote de notificação .

No começo, eu tinha um código parecido com este:

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

Eu queria acrescentar uma nova linha Hello World!na função doitacima, mas não na função acima, porque isso seria bastante trivial, mas handlerposteriormente como este abaixo:

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

Depois go run:

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

Depois de pesquisar um pouco no Google, encontrei essa pergunta no SO .

Atualizei meu código para:

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

É isso que eu deveria fazer? Meus erros de compilador desapareceram, então acho que isso é muito bom. Isso é eficiente? Você deveria fazer diferente?

Alfred
fonte

Respostas:

291

De acordo com a especificação Go :

Para uma expressão x do tipo de interface e um tipo T, a expressão primária x. (T) afirma que x não é nulo e que o valor armazenado em x é do tipo T.

Uma "asserção de tipo" permite declarar que um valor de interface contém um determinado tipo concreto ou que seu tipo concreto satisfaz outra interface.

No seu exemplo, você estava afirmando que os dados (interface do tipo {}) possuem a cadeia de caracteres do tipo concreto. Se você estiver errado, o programa entrará em pânico durante a execução. Você não precisa se preocupar com eficiência, a verificação requer apenas a comparação de dois valores de ponteiro.

Se você não tinha certeza se era uma sequência ou não, poderia testar usando a sintaxe de dois retornos.

str, ok := data.(string)

Se os dados não forem uma sequência, ok será falso. Em seguida, é comum agrupar essa declaração em uma declaração if da seguinte maneira:

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

Asserção de tipo

Isso é conhecido como type assertion golang, e é uma prática comum.

Aqui está a explicação de um tour de go :

Uma asserção de tipo fornece acesso ao valor concreto subjacente de um valor de interface.

t := i.(T)

Esta declaração afirma que o valor da interface i contém o tipo concreto T e atribui o valor T subjacente à variável t.

Se eu não segurar um T, a instrução irá desencadear um pânico.

Para testar se um valor de interface contém um tipo específico, uma asserção de tipo pode retornar dois valores: o valor subjacente e um valor booleano que relata se a asserção foi bem-sucedida.

t, ok := i.(T)

Se eu mantiver um T, então t será o valor subjacente e ok será verdadeiro.

Caso contrário, ok será falso et será o valor zero do tipo T e não ocorrerá pânico.

NOTA: o valor ideve ser do tipo interface .

Armadilhas

Mesmo se ifor um tipo de interface, []inão é do tipo interface. Como resultado, para converter []iem seu tipo de valor, precisamos fazer isso individualmente:

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

atuação

Quanto ao desempenho, ele pode ser mais lento do que o acesso direto ao valor real, conforme mostrado nesta resposta do stackoverflow .

cizixs
fonte
13
//an easy way:
str := fmt.Sprint(data)
Yuanbo
fonte
21
Adicione algumas explicações com a resposta de como esta resposta ajuda o OP a corrigir o problema atual
#
2

Conforme solicitado por @ ρяσѕρєя, uma explicação pode ser encontrada em https://golang.org/pkg/fmt/#Sprint . Explicações relacionadas podem ser encontradas em https://stackoverflow.com/a/44027953/12817546 e em https://stackoverflow.com/a/42302709/12817546 . Aqui está a resposta de @ Yuanbo na íntegra.

package main

import "fmt"

func main() {
    var data interface{} = 2
    str := fmt.Sprint(data)
    fmt.Println(str)
}
Tom J
fonte
1
Eu acho que você pode combinar as duas respostas simplesmente editando as @ Yuanbo's - vocês dois serão creditados e somarão sua respectiva pontuação de 'utilidade'
Gwyneth Llewelyn