簡體   English   中英

如何鍵入斷言動態反射生成的結構接口

[英]How to type assert a dynamically reflection-generated struct interface

我是 Go 的新手,所以如果這是一個微不足道的問題,請多多包涵。 我正在使用自制的“類型注冊表”將類型名稱映射到它們的類型,以便根據指向各種類型名稱的用例動態生成它們(我基本上是在嘗試一個簡單的解決方案來解決多態聚合 JSON 響應Elasticsearch 中的結構,但當然這可以應用於許多其他動態/多態情況)。 我在這個問題中使用了 dolmen 提供的解決方案: 有沒有辦法從字符串創建結構的實例?

var typeRegistry = make(map[string]reflect.Type)

func registerType(typedNil interface{}) {
    t := reflect.TypeOf(typedNil).Elem()
    typeRegistry[t.Name()] = t
}

func init() {
    registerType((*playlistIDAggregation)(nil))
    registerType((*srcIDAggregation)(nil))
    registerType((*assetIDAggregation)(nil))
}

func makeInstance(name string) interface{} {
    return reflect.New(typeRegistry[name]).Elem().Interface()
}

然后,我想使用動態生成的結構作為 ES 響應中聚合節點的 JSON 解組目標:

playlistIDAgg := makeInstance("playlistIDAggregation")
err = json.Unmarshal(esResponse.Aggregations, &playlistIDAgg)

這不像我想要的那樣工作,因為 Unmarshal 試圖解組到一個空接口而不是底層結構類型。 它將數據放在 playlistIDAgg 變量中的“數據”節點下,這些數據字段當然是map[string]interface{} 我是否只是缺少輸入斷言我的playlistIDAgg接口的方法,還是有更好的方法來做到這一點?

編輯---評論中的問題讓我意識到對這個問題的編輯早就應該了。 在我的特殊情況下,我定義的用於綁定到 Elasticsearch 返回的 Bucket 聚合的結構具有相似的結構,並且僅因它們的根 JSON 標記而異,ES 使用該標記命名聚合並對其進行強類型化。 例如

type <name>Aggregation struct {
    Agg BucketAggregationWithCamIDCardinality `json:"<name>"`
}

因此,不是類型注冊表,我的特定問題可以通過基於特定用例在結構上動態設置 JSON 標記來解決。

此外,一個更重但更強大的選擇是利用 Oliver Eilhard 的 Elasticsearch Go 客戶端庫,稱為 Elastic,它內置了對所有 ES 聚合響應結構的支持: https : //github.com/olivere/elastic/

我通過獲取元素的地址並添加具有公開字段的目標結構來更改makeInstance函數。

func makeInstance(name string) interface{} {
    return reflect.New(typeRegistry[name]).Elem().Addr().Interface()
}

這是工作代碼

package main

import (
    "encoding/json"
    "fmt"
    "reflect"
)

type playlistIDAggregation struct {
    PlaylistID string
}

type srcIDAggregation struct {
    SrcID string
}

type assetIDAggregation struct {
    AssetID string
}

var typeRegistry = make(map[string]reflect.Type)

func registerType(typedNil interface{}) {
    t := reflect.TypeOf(typedNil).Elem()
    typeRegistry[t.Name()] = t
}

func init() {
    registerType((*playlistIDAggregation)(nil))
    registerType((*srcIDAggregation)(nil))
    registerType((*assetIDAggregation)(nil))
}

func makeInstance(name string) interface{} {
    return reflect.New(typeRegistry[name]).Elem().Addr().Interface()
}

func main() {
    playlistIDAgg := makeInstance("playlistIDAggregation")
    fmt.Printf("Type = %[1]T => %#[1]v\n", playlistIDAgg)
    err := json.Unmarshal([]byte(`{"PlayListID": "dummy-id"}`), &playlistIDAgg)
    if err != nil {
        panic(err)
    }
    fmt.Printf("Type = %[1]T => %#[1]v\n", playlistIDAgg)
}

https://play.golang.org/p/dn19_iG5Xjz

暫無
暫無

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

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