簡體   English   中英

如何從 interface{} 轉換為 struct 實例

[英]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.

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