Преобразование интерфейса{} в карту в Golang
Я пытаюсь создать функцию, которая может принимать следующие
*struct
[]*struct
map[string]*struct
здесь структура может быть любой структурой, а не только конкретной.
Преобразование интерфейса в *struct
или []*struct
работает нормально.
Но давая ошибку для карты.
после отражения он показывает, что это map [], но дает ошибку при попытке итерации по диапазону.
здесь код
package main
import (
"fmt"
"reflect"
)
type Book struct {
ID int
Title string
Year int
}
func process(in interface{}, isSlice bool, isMap bool) {
v := reflect.ValueOf(in)
if isSlice {
for i := 0; i < v.Len(); i++ {
strct := v.Index(i).Interface()
//... proccess struct
}
return
}
if isMap {
fmt.Printf("Type: %vn", v) // map[]
for _, s := range v { // Error: cannot range over v (type reflect.Value)
fmt.Printf("Value: %vn", s.Interface())
}
}
}
func main() {
b := Book{}
b.Title = "Learn Go Language"
b.Year = 2014
m := make(map[string]*Book)
m["1"] = &b
process(m, false, true)
}
есть ли способ, чтобы преобразовать interface{}
для отображения и итерации или получения элементов.
2 ответов
Если значение карты может быть любого типа, то используйте reflect для итерации по карте:
if v.Kind() == reflect.Map {
for _, key := range v.MapKeys() {
strct := v.MapIndex(key)
fmt.Println(key.Interface(), strct.Interface())
}
}
Если есть небольшой и известный набор типов структур, то тип переключателя можно использовать в:
func process(in interface{}) {
switch v := in.(type) {
case map[string]*Book:
for s, b := range v {
// b has type *Book
fmt.Printf("%s: book=%v\n" s, b)
}
case map[string]*Author:
for s, a := range v {
// a has type *Author
fmt.Printf("%s: author=%v\n" s, a)
}
case []*Book:
for i, b := range v {
fmt.Printf("%d: book=%v\n" i, b)
}
case []*Author:
for i, a := range v {
fmt.Printf("%d: author=%v\n" i, a)
}
case *Book:
fmt.Ptintf("book=%v\n", v)
case *Author:
fmt.Printf("author=%v\n", v)
default:
// handle unknown type
}
}
вам не нужно размышлять здесь. Попробуйте:
v, ok := in.(map[string]*Book)
if !ok {
// Can't assert, handle error.
}
for _, s := range v {
fmt.Printf("Value: %v\n", s)
}
то же самое касается остальной части вашей функции. Похоже, вы используете отражение, когда вам будет лучше служить тип переключателя.
кроме того, если вы настаиваете на использовании отражения здесь (что не имеет большого смысла), вы также можете использовать Value.MapKeys
С результатом от вашего ValueOf (см. ответ https://stackoverflow.com/a/38186057/714501)