не може конвертувати дані (інтерфейс типу {}) у рядок типу: потребує затвердження типу


178

Я досить новий, і я грав з цим пакетом сповіщень .

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

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)

Після трохи гуглиння я знайшов це питання на 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)
}

Це те, що я мав робити? Мої компіляторські помилки зникли, тому я гадаю, що це досить добре? Це ефективно? Чи варто робити це інакше?

Відповіді:


292

Відповідно до специфікації Go :

Для виразу x інтерфейсного типу та типу T основний вираз x. (T) стверджує, що x не є нульовим і що значення, збережене у x, має тип T.

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

У вашому прикладі ви стверджували, що дані (інтерфейс типу {}) містить конкретний рядок типу. Якщо ви помиляєтесь, програма буде панікувати під час виконання. Не потрібно турбуватися про ефективність, перевірка вимагає лише порівняння двох знаків вказівника.

Якщо ви не впевнені, чи це рядок чи ні, ви можете перевірити, використовуючи два синтаксису повернення.

str, ok := data.(string)

Якщо дані не є рядком, нормально буде помилково. Тоді звичайно загортати таку заяву в оператор if, як:

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

29

Затвердження типу

Це відомо як type assertionголанг, і це звичайна практика.

Ось пояснення з екскурсії :

Затвердження типу забезпечує доступ до базового конкретного значення інтерфейсу.

t := i.(T)

Це твердження стверджує, що значення інтерфейсу i містить конкретний тип T і присвоює основне значення T змінній t.

Якщо я не тримаю T, це твердження викликає паніку.

Щоб перевірити, чи містить інтерфейс певний тип, твердження типу може повернути два значення: базове значення і булеве значення, яке повідомляє про те, чи підтвердження вдалося.

t, ok := i.(T)

Якщо у мене T, то t буде основним значенням, а нормально - істиною.

Якщо ні, нормально буде помилково, а t - нульове значення типу T, і паніки не виникає.

ПРИМІТКА: значення iповинно бути типом інтерфейсу .

Підводні камені

Навіть якщо iце тип інтерфейсу, []iце не тип інтерфейсу. Як результат, щоб перетворити []iйого на тип значення, ми повинні зробити це окремо:

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

Продуктивність

Що стосується продуктивності, то це може бути повільніше, ніж прямий доступ до фактичного значення, як показано у цій відповіді stackoverflow .


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

21
Додайте пояснення з відповіддю, як ця відповідь допоможе ОП у вирішенні поточного питання
ρяσѕρєя K

3

За запитом @ ρяσѕρєя пояснення можна знайти за посиланням https://golang.org/pkg/fmt/#Sprint . Пов’язані пояснення можна знайти на веб- сайті https://stackoverflow.com/a/44027953/12817546 та на веб- сайті https://stackoverflow.com/a/42302709/12817546 . Ось відповідь @ Yuanbo повністю.

package main

import "fmt"

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

1
Я думаю, ви могли б поєднати обидві відповіді, просто відредагувавши @ Yuanbo's - вам обом буде зараховано та складете відповідний бал «корисності» 😉
Гвінет
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.