Как заполнить интерфейс map [string] {}, когда мое значение имеет тип структуры?

#go

#Вперед

Вопрос:

Я хочу создать JSON-эквивалент PurchaseOrder структуры ниже:

 type PurchaseOrder struct {
    State      string
    FsmName    string
    Supplier   string
    Receiver   string
    TradeItems map[string]PRTradeItem
}

type PRTradeItem struct {
    Quantity float64 `json:"quantity"`
    Supplier string  `json:"supplier"`
    Receiver string  `json:"receiver"`

    PricePerUnit float64 `json:"pricePerUnit"`
}
  

Для этого я сделал следующее:

 po := make(map[string]interface{})
po["Sender"] = "org2"
po["Receiver"] = "org1"
po["TradeItems"] = make(map[string]PRTradeItem)
po["TradeItems"]["sku1"] = PRTradeItem{Quantity: 100, Supplier: "org2", Receiver: "org1", PricePerUnit: 10.5}
poAsBytes, _ := JSON.Marshal(po)
  

Ошибка, которую я получаю, это:

недопустимая операция: po[«TradeItems»][«sku1»] (интерфейс типа {} не поддерживает индексацию).

Немного осмотревшись, я добавил следующие строки в код, и это сработало.

 internalMap, ok := po["TradeItems"].(map[string]PRTradeItem)
if !ok{

    panic("why???")
}
if ok{  
    internalMap["sku1"] = PRTradeItem{Quantity:100,Supplier:"org2", Receiver:"org1", PricePerUnit:10.5}
}
  

Я не совсем понимаю, что означает эта строка

 internalMap, ok := po["TradeItems"].(map[string]PRTradeItem)
  

Может кто-нибудь, пожалуйста, объяснить?

Комментарии:

1. Это утверждение типа . v.(T) утверждает, что значение v имеет тип T . Таким образом, po["TradeItems"].(map[string]PRTradeItem) утверждается, что значение, связанное с "TradeItems" ключом в map po , имеет тип map[string]PRTradeItem .

2. Конечно, но зачем это нужно? Я знаю тип po["TradeItems"] . Пожалуйста, объясните подробно. Почему я должен утверждать?

3. Почему бы вам просто не маршалировать свою структуру напрямую? Зачем беспокоиться о карте?

4. Вы должны ввести assert , потому что это единственный способ получить доступ к базовому типу данных интерфейса.

5. Потому что Go — это статически типизированный язык, и вы определили po тип значения как interface{} , поэтому результатом po[somekey] всегда будет значение типа interface{} .

Ответ №1:

Я хочу создать JSON-эквивалент структуры PurchaseOrder ниже:

 type PurchaseOrder struct {
    State      string
    FsmName    string
    Supplier   string
    Receiver   string
    TradeItems map[string]PRTradeItem
}
  

Самый простой способ — это:

 po := PurchaseOrder{
    State:      "paid",
    Supplier:   "Acme, Inc.",
    TradeItems: map[string]PRTradeItem{
        "sku1": PRTradeItem{Quantity: 100, Supplier: "org2", ... },
    },
}
poAsBytes, err := json.Marshal(po)
  

Забудьте о своих po := make(map[string]interface{}) и ручных манипуляциях с картой.

Если вам нужно управлять ключами JSON в вашем PurchaseOrder объекте, добавьте соответствующие json теги, как вы сделали для PRTradeItem определения.

Ответ №2:

Я знаю тип po["TradeItems"] . Пожалуйста, объясните подробно. Почему я должен утверждать?

Вы делаете, но компилятор не делает. У вашего po есть тип map[string]interface{} . Таким образом, po["TradeItems"] in po["TradeItems"]["sku1"] возвращает объект типа interface{} , с которым вы не можете сделать ничего полезного (не без отражения или утверждения типа).

Отсюда необходимость подсказать компилятору утверждение этого типа.