#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"
ключом в mappo
, имеет тип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{}
, с которым вы не можете сделать ничего полезного (не без отражения или утверждения типа).
Отсюда необходимость подсказать компилятору утверждение этого типа.