[英]How to convert from an interface{} to a struct instance
我正在研究 Go 模塊實現以抽象與其他對等方的通信。 該模塊背后的想法是通過 MQ 以標准消息格式發送/接收消息,其中幾乎可以攜帶任何類型的“實體”。 但我發現很難解決 Go 中的類型轉換。
這是我正在嘗試做的一個片段( https://play.golang.org/p/Orb1vNdulY1 )。
type Message struct {
Code string
Entity interface{}
}
type Cartoon struct {
Name string
Show string
}
func main() {
cartoon := Cartoon{Name: "Doug Funnie", Show: "Doug"}
msg := Message{Code: "12345", Entity: cartoon}
payload, err := json.Marshal(msg)
fmt.Println("JSON Sent:", string(payload))
// Here json message gets sent to a MQ broker
// Here json message gets read by a consumer
var message Message
err = json.Unmarshal(payload, &message)
fmt.Println("Message Received:", message)
var cart Cartoon
cart = message.Entity.(Cartoon)
fmt.Println("Cartoon Received:", cart)
}
在這一行,我收到以下錯誤:
cart = message.Entity.(Cartoon)
恐慌:界面轉換:界面{}是地圖[字符串]界面{},而不是main.Cartoon
問題是,由於它旨在成為“通用”實體類型的模塊,因此在將消息傳遞給消費者應用程序之前,我不知道實體類型(結構)。
所以我需要一種方法將結構的實例傳遞給應用程序,甚至允許消費者應用程序轉換為它期望接收的類型(結構)。
即使有一種更簡單優雅的方式來做我想做的事,即使我必須更改我的 Message 結構,我也可以考慮解決方案。
我想出解決此問題的唯一方法是將Message.Entity轉換為包含原始 json 內容的字符串字段,然后消費者應用程序將其解組為所需的類型。 不是那么優雅。
原始字符串/json 解決方案( https://play.golang.org/p/c9bgAbI7SZh )。
有什么想法嗎?
該問題詢問如何將interface{}
轉換為 Go 類型。 OPs 應用程序中更高級別的目標是將 JSON 消息的變體部分轉換為 Go 類型。 這里回答了更高層次的問題。
如果在解組 JSON 時類型已知,則將 Entity 字段設置為指向適當類型值的指針:
var cart Cartoon
message := &Message{Entity: &cart}
err := json.Unmarshal(payload, message)
如果在解碼消息的不變部分之前類型未知,則使用json.RawMessage捕獲實體 JSON。 一旦知道類型,就解碼 JSON。
var entity json.RawMessage
message := &Message{Entity: &entity}
err := json.Unmarshal(payload, &message)
// ... determine target entity type using message
var cart Cartoon
err = json.Unmarshal(entity, &cart)
另一種選擇是創建類型注冊表:
var messageTypes = map[string]reflect.Type{
"cartoon": reflect.TypeOf(&Cartoon{}).Elem(),
}
並從注冊表中解碼為一種類型:
var entity json.RawMessage
message := &Message{Entity: &entity}
err = json.Unmarshal(payload, message)
if err != nil {
// handle error
}
message.Entity = nil
if t := messageTypes[message.Type]; t != nil {
v := reflect.New(t).Interface()
err := json.Unmarshal(entity, v)
if err != nil {
// handle error
}
message.Entity = v
}
有一個解決方案(它不是那么優雅,)。 如果您保持結構不變。
tmp, ok := message.Entity.(map[string]interface{})
if ok {
cart.Name = tmp["Name"].(string) // inside bracket depends to the json
cart.Show = tmp["Show"].(string)
}
https://play.golang.org/p/T9i7pYlk96h
你也可以使用反射。
看起來我可以用一個名為 mapstructure 的庫來解決這個問題。
var cart Cartoon
mapstructure.Decode(message.Entity, &cart)
fmt.Println("cartoon:", cart)
我在這里做了一個成功的測試: https://play.golang.org/p/J9V-SFz1pJE
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.