сериализация golang структур в уникальном неструктурированном хранилище данных - PullRequest
0 голосов
/ 10 июня 2019

У меня есть дилемма для хранения некоторых данных в неструктурированном поле.Допустим, у меня есть эти для хранения:

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
}

Я сравнил оба, у них примерно одинаковое время обработки и одинаковое использование памяти, но мне интересно, какой из них может быть более идиоматичным?

...