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