web-dev-qa-db-ja.com

インターフェイス{}をGolangのマップに変換します

私は以下を受け入れることができる関数を作成しようとしています

*struct
[]*struct
map[string]*struct

ここで、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: %v\n", v)     // map[]
        for _, s := range v {           // Error: cannot range over v (type reflect.Value)
            fmt.Printf("Value: %v\n", 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{}を変換して、その要素をマッピングおよび反復または取得する方法はありますか。

16
SamTech

マップ値が任意のタイプである場合、reflectを使用してマップを反復処理します。

if v.Kind() == reflect.Map {
    for _, key := range v.MapKeys() {
        strct := v.MapIndex(key)
        fmt.Println(key.Interface(), strct.Interface())
    }
}

遊び場の例

構造タイプの小さくて既知のセットがある場合、 type switch を使用できます。

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
   }
}
24
Cerise Limón

ここに反映する必要はありません。試してください:

v, ok := in.(map[string]*Book)
if !ok {
    // Can't assert, handle error.
}
for _, s := range v {
    fmt.Printf("Value: %v\n", s)
}

他の機能についても同じことが言えます。 type switch を使用したほうがよい場合に、リフレクションを使用しているように見えます。


あるいは、ここでリフレクションを使用することを主張する場合(あまり意味がありません)、 Value.MapKeys ValueOfからの結果(回答を参照してください https://stackoverflow.com/a/38186057/714501

20
cnicutar