I'm looking to understand which is the most suitable approach to solve the following problem.

I have a struct that represents the data to be serialised as part of a JSON response. A property on this struct config can be one of three possible structs, however, the only way I know to represent this is using the type interface{} and have the caller type assert the property.

type Response struct {
    Field1 string      `json:"field1"`
    Field2 int         `json:"field2"`
    Config interface{} `json:"config"`
}

type ConfigOne struct {
    SomeField string
}

type ConfigTwo struct {
    SomeField int
}

type ConfigThree struct {
    SomeField bool
}

Then I can have New style functions to create the right instance for me:

func NewConfigTwo() *Response {
    return &Response{
        Field1: "hello",
        Field2: 1,
        Config: ConfigTwo{
            SomeField: 22,
        },
    }
}

Is there a better way to represent a field with a enum like type of structs? Or is this as good as I can make it?

I'd appreciate any clarity or suggestions on how best to achieve this.

1 Answers

2
Eli Bendersky On Best Solutions

Essentially, you're trying to implement an algebraic data type here. To expand on @mkopriva's comment, take a look at this post: Go and algebraic data types. Essentially you'll specify a non-empty interface such that all possible types implement a method and others don't satisfy the interface "by chance" (whereas every type implements interface{}) and then use type switches.

Something like (untested):

type Response struct {
    Field1 string      `json:"field1"`
    Field2 int         `json:"field2"`
    Config Configable  `json:"config"`
}

type Configable interface {
    isConfig()
}

type ConfigOne struct {
    SomeField string
}

func (ConfigOne) isConfig() {}

// ... and so on for other Config* types