Итерация по массиву интерфейсов

Я написал код:

switch v.(type) {
        case []interface{}:
            fmt.Println(reflect.TypeOf(v))
            for index, element := range v {
                fmt.Println("Inside for")
            }
        default:
            fmt.Println("I don't know how to handle this.")
        }

Теперь мой reflect.TypeOf(v) выводит тип как []interface {} . Но я не могу перебирать массив интерфейсов. Я сталкиваюсь с ошибкой: cannot range over v (type interface {}). Может кто-нибудь объяснить мне, почему? Кроме того, каков обходной путь?


go
person Jerry Ajay    schedule 10.03.2015    source источник


Ответы (2)


В переключателе типа, если вы хотите получить доступ к переменной, приведенной к соответствующему типу, просто используйте что-нибудь как switch x := v.(type) и в каждом случае переключатель x будет иметь соответствующее значение. В спецификации есть такой пример. Вы даже можете сделать switch v := v.(type), и в операторе switch будет теневая версия v.

E.g.:

switch x := v.(type) {
case []interface{}:
        fmt.Printf("got %T\n", x)
        for i, e := range x {
                fmt.Println(i, e)
        }
default:
        fmt.Printf("I don't know how to handle %T\n", v)
}

детская площадка

Также обратите внимание, что вы можете просто использовать %T с fmt.Printf вместо (напрямую) использования пакета Reflect, когда вы просто хотите напечатать тип переменной.

Наконец, обратите внимание, что переключатель типа — это то, что вам нужно, если у вас есть несколько предложений не по умолчанию, но если, как в вашем примере, у вас действительно есть только один интересующий вас тип, вместо этого вы должны сделать что-то вроде:

if x, ok := v.([]interface{}); ok {
        fmt.Printf("got %T\n", x)
        for i, e := range x {
                fmt.Println(i, e)
        }
} else {
        fmt.Printf("I don't know how to handle %T\n", v)
}
person Dave C    schedule 10.03.2015

Вы всегда можете использовать v.([]interface{}). Я столкнулся с той же проблемой при попытке проанализировать разнородные объекты json, которые нужно было рассматривать как интерфейсы.

Хотя это может не сработать в вашем цикле, если вы заранее не знаете что-то о своих данных.

person ProfOak    schedule 10.03.2015
comment
Я только что изменил свой switch v.(type) на switch vv := v.(type), и все стало нормально работать, когда я переключаюсь на vv. Спасибо, в любом случае. - person Jerry Ajay; 10.03.2015
comment
Я должен был отметить в своем ответе, что если у вас есть только два случая в переключателе (т.е. вы обрабатываете только один тип), вам действительно следует использовать vv, ok := v.([]interface{}) и просто проверять ok. Переключатель типа используется, когда вы хотите обрабатывать несколько типов. - person Dave C; 10.03.2015