У меня есть дилемма для хранения некоторых данных в неструктурированном поле.Допустим, у меня есть эти для хранения:
package main
type FoodType string
const (
BeefFood FoodType = "beef"
ChickenFood FoodType = "chicken"
)
type FoodI interface {
Prepare()
GetType() FoodType
}
type FoodContainer struct {
FoodI
}
type Chicken struct {
Way string
}
func (c *Chicken) Prepare() {}
func (c *Chicken) GetType() FoodType {
return ChickenFood
}
type Beef struct {
Way string
}
func (b *Beef) Prepare() {}
func (b *Beef) GetType() FoodType {
return BeefFood
}
Допустим, я выбрал json в качестве сериализатора (я, вероятно, пойду на msgpack, но это уже другая история).
Как вы думаете, каким образомявляется наиболее подходящим:
Решение 1
один контейнер, который содержит все типы сообщений, и просто используйте маршал / unmarshal по умолчанию:
package main
type FoodContainer struct {
Chicken *Chicken `json:"chicken"`
Beef *Beef `json:"beef"`
}
А затем мне просто нужно проверить, какое из полей равно нулю, чтобы знать, что с ним делать.
Решение 2
Более «типизированное» решение, с интерфейсами и FoodType
package main
import (
"encoding/json"
"fmt"
)
type FoodContainer struct {
FoodType
FoodI
}
func (fc *FoodContainer) MarshalJSON() ([]byte, error) {
return json.Marshal(&FoodContainerT{
FoodType: fc.FoodI.GetType(),
FoodI: fc.FoodI,
})
}
func (fc *FoodContainer) UnmarshalJSON(b []byte) error {
var fct struct {
FoodType
}
if err := json.Unmarshal(b, &fct); err != nil {
return fmt.Errorf("fc UnmarshalJSON: %v", err)
}
switch fct.FoodType {
case ChickenFood:
fmt.Printf("Yeah, Chickenfood: %v\n", fct.FoodType)
var fi struct {
FoodI Chicken
}
if err := json.Unmarshal(b, &fi); err != nil {
return fmt.Errorf("chicken UnmarshalJSON: %v", err)
}
fmt.Printf("%#v", fi.FoodI)
default:
return fmt.Errorf("no known FoodType found")
}
return nil
}
Я сравнил оба, у них примерно одинаковое время обработки и одинаковое использование памяти, но мне интересно, какой из них может быть более идиоматичным?