Утверждение типа со встроенными типами

type BizError struct {
    Code string
    Mesg string
}

type ApiReply struct {
    Err BizError
}

type GetDataReply struct {
    Data interface{}
    ApiReply
}

с приведенным выше определением я хочу сделать следующее:

func Func1(data interface{}) {
    switch data.(type) {
    case ApiReply:
        data.(ApiReply).Err.Code = "0"
    }
}

Ключевая проблема заключается в том, что в Func1 переключатель типа не знает никаких новых типов, которые встраивают ApiReply, это «общий» обработчик. Хотя переданный ему data на самом деле является «дочерним классом» ApiReply. По-видимому, в Go вы не можете утверждать тип GetDataReply для ApiReply.

Как я могу справиться с этим случаем, чтобы в Func1 мне не нужно было явно объявлять все возможные структуры, которые могут встраивать ApiReply?


person xrfang    schedule 09.06.2018    source источник
comment
@xrfang Что-то вроде этого? play.golang.org/p/IKxIj8XoOLc   -  person mkopriva    schedule 09.06.2018
comment
@mkopriva да, это близко к тому, что я хочу   -  person xrfang    schedule 12.06.2018


Ответы (1)


Вы пытаетесь внедрить систему стилей наследования на ходу. Встраивание структур не является наследованием и не должно рассматриваться или рассматриваться как таковое. Это анти-паттерн на ходу, и он обычно работает не так, как вы бы хотели или ожидали.

Вместо этого более идиоматическим подходом к этому было бы определение интерфейса (или пары интерфейсов) и реализация в ваших типах ответов необходимых методов для согласования.

type ApiReply interface {
    Status() (string, string)

    Body() (io.Reader, error)
}

type BizError struct {
    Code string
    Mesg string
}

func (b BizError) Status() (string, string) {
    return b.Code, b.Mesg
}

func (b BizError) Body() (io.Reader, error) {
    return nil, errors.New("BizError never contains a body")
}

Затем вы должны реализовать ApiReply в структурах другого типа ответа. Я, конечно, догадываюсь, что вам здесь действительно нужно, но, надеюсь, это уясняет суть.

И если вы обнаружите, что это необходимо, теперь вы можете выполнить переключение типа для экземпляра ApiReply, который вы получаете, и в особом случае для любых базовых типов, если это абсолютно необходимо.

person Thomas    schedule 09.06.2018