2016-07-04 69 views
9

我試圖創造一種可以接受以下轉換接口{}映射在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: %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{}映射和迭代或得到它的元素。

回答

10

如果映射值可以是任何類型,然後使用反映通過地圖來迭代:

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

playground example

如果療法E公司的一個小組已知的結構類型,然後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 
    } 
} 
+0

不錯。我在你的貼子上添加了MapKeys到我的答案部分! – cnicutar

+0

工作絕對好。非常感謝。 – SamTech

15

你不需要在這裏反映。嘗試:

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

+1

結構在這裏也能像書,Auther,發佈任何結構...的結構的類型轉換類型必須知道,我沒有。 – SamTech

+0

@SamTech結構的類型是不是「已知」?您可以切換所有想要處理的類型。 – cnicutar

+0

我的意思是,我怎麼知道我是否必須鍵入開關傳遞接口映射[字符串] *書或地圖[字符串] * Auther? – SamTech