簡體   English   中英

golang - 對嵌入式結構的反思

[英]golang - reflection on embedded structs

給定一個像這樣的結構:

type B struct {
    X string
    Y string
}

type D struct {
    B
    Z string
}

我想反思 D 並進入 X、Y、Z 領域。

直觀地說,在嘗試解決方案之前,我假設我能夠遍歷結構 D 並使用反射(X、Y、Z)獲取所有字段,而不必處理 B。

但是正如您所看到的,我只看到使用反射的嵌入式結構 B 而不是它的字段。

http://play.golang.org/p/qZQD5GdTA8

有沒有辦法讓 B 在反射到 D 時完全透明?

我為什么要這個?

對一個公共結構(此處示例中的 B)進行成像,該結構通過使用嵌入在多個其他結構中使用。 使用反射,嘗試將 D 復制到不同包中的另一個類似結構中。 用於復制的目標結構將具有平面布局的所有屬性(沒有嵌入)。 因此,從源到目標存在不匹配(嵌入與無嵌入),但所有平鋪的屬性都是相同的。 我不想為每個結構創建自定義解決方案。

您期望的“透明度”只是語法糖,與數據表示無關。 如果您想擁有一個扁平化數據結構的函數,則必須自己編寫。

例如(在玩):

func DeepFields(iface interface{}) []reflect.Value {
    fields := make([]reflect.Value, 0)
    ifv := reflect.ValueOf(iface)
    ift := reflect.TypeOf(iface)

    for i := 0; i < ift.NumField(); i++ {
        v := ifv.Field(i)

        switch v.Kind() {
        case reflect.Struct:
            fields = append(fields, DeepFields(v.Interface())...)
        default:
            fields = append(fields, v)
        }
    }

    return fields
}

使用以下代碼收集所有提升的字段名稱作為映射m鍵:

func collectFieldNames(t reflect.Type, m map[string]struct{}) {

    // Return if not struct or pointer to struct.
    if t.Kind() == reflect.Ptr {
        t = t.Elem()
    }
    if t.Kind() != reflect.Struct {
        return
    }

    // Iterate through fields collecting names in map.
    for i := 0; i < t.NumField(); i++ {
        sf := t.Field(i)
        m[sf.Name] = struct{}{}

        // Recurse into anonymous fields.
        if sf.Anonymous {
            collectFieldNames(sf.Type, m)
        }
    }
}

像這樣使用它:

m := make(map[string]struct{})
collectFieldNames(reflect.TypeOf((*D)(nil)), m)
for name := range m {
    fmt.Println(name)
}

在操場上運行它

該程序按照問題的要求打印 X、Y 和 Z,但也打印 B,因為 B 也是字段名稱。

此答案中的此功能可以改進:

  • 不要吹噓遞歸類型定義。
  • 不要在層次結構中包含在同一級別重復的名稱。

encoding/json/encode.go 中typeField函數處理這兩個問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM