Не может преобразовать данные (тип интерфейса {}) для ввода строки: require type assertion

Я довольно новичок, и я играл с этим пакетом notify.

Сначала у меня был код, который выглядел так:

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

Я хотел добавить новую строку в Hello World!, но не в функции doit выше, потому что это было бы довольно тривиально, но в handler после этого, как показано ниже:

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

После go run:

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

После немного Googling я нашел этот вопрос на SO.

Затем я обновил свой код до:

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

Это то, что я должен был делать? Мои ошибки компилятора исчезли, поэтому я думаю, что это очень хорошо? Является ли это эффективным? Если вы делаете это по-другому?

Ответ 1

В соответствии с Спецификация Go:

Для выражения x типа интерфейса и типа T первичное выражение x. (T) утверждает, что x не равно nil и что значение, хранящееся в x, имеет тип T.

"Утверждение типа" позволяет объявить значение интерфейса, содержащее определенный конкретный тип, или что его конкретный тип удовлетворяет другому интерфейсу.

В вашем примере вы утверждали данные (тип interface {}) имеет строку конкретного типа. Если вы ошибаетесь, программа будет паниковать во время работы. Вам не нужно беспокоиться об эффективности, проверяя, просто нужно сравнить два значения указателя.

Если вы не уверены, что это была строка или нет, вы можете протестировать, используя два синтаксиса возврата.

str, ok := data.(string)

Если данные не являются строкой, ok будет false. Затем принято обертывать такое утверждение в оператор if следующим образом:

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

Ответ 2

Утверждение типа

Это известно как type assertion в golang, и это обычная практика.

Вот объяснение от тур по пути:

Утверждение типа предоставляет доступ к значению интерфейса, лежащему в основе конкретного значения.

t := i.(T)

В этом утверждении утверждается, что значение интерфейса я содержит конкретный тип T и присваивает базовое значение T переменной t.

Если я не содержит T, инструкция вызовет панику.

Чтобы проверить, имеет ли значение интерфейса определенный тип, утверждение типа может возвращать два значения: базовое значение и логическое значение, сообщающее, удалось ли это утверждение.

t, ok := i.(T)

Если я содержит T, то t будет базовым значением, а ok будет истинным.

Если нет, ok будет ложным и t будет нулевым значением типа T, и не будет паники.

ПРИМЕЧАНИЕ. Значение i должно быть типом интерфейса.

Ловушки

Даже если i является типом интерфейса, []i не является типом интерфейса. В результате, чтобы преобразовать []i в свой тип значения, мы должны сделать это индивидуально:

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

Производительность

Что касается производительности, это может быть медленнее, чем прямой доступ к фактическому значению, как показано в fooobar.com/questions/53318/....

Ответ 3

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