Json解码为struct,根据路径使用不同的请求类型

I want to decode json to struct. My structs look like that:

type message struct {
 Request baseRequest `json:"request"`  //actually there should be other type here, but I can't think of what it could be
 Auth auth           `json:"auth"`
}

type baseRequest struct {
  Foo string `json:"foo" validate:"required"`
}

type createRequest struct {
  baseRequest
  Bar string `json:"bar" validate:"required"`
}

type cancelRequest struct{
  baseRequest
  FooBar string `json:"foo_bar" validate:"required"`
}

I want to compose createRequest with baseRequest. All my code is revolving around passing message type in chain of responsibility pattern. I have implemented a handler, that creates a pointer to empty message struct, that is used by jsonReader() function. For /create path I want to use createRequest instead of baseRequest, and for /cancel path I want to use cancelRequest. So for example in:

func (factory *HandlerFactory) Create() http.Handler {
    create := func() *message { return &message{} }
    return factory.defaultChain(createNewMessage, nil)
}

I want to change the type of message.Request() to createRequest. And in:

func (factory *HandlerFactory) Cancel() http.Handler {
    create := func() *message { return &message{} }
    return factory.defaultChain(createNewMessage, nil)
}

I want to change the type of message.Request to cancelRequest. How can I achieve something like that in Go?

Unfortunately what you are trying to do is not really how Go works, since Go does not have polymorphism - createRequest and cancelRequest do not inherit from baseRequest, they contain a baseRequest. So when you have baseRequest in your message struct, it can't be anything other than a baseRequest.

You may need to use separate types for each message. One for the cancel request, and a different one for the create request.

Here is an article discussing inheritance and composition in Go, and contrasts it with Java. It should help you grok how struct embedding works in Go.

Actually, I found the way. You could implement message like this:

type message struct {
  Request request `json:"request"`  //actually there should be other type here, but I can't think of what it could be
  Auth auth           `json:"auth"`
}

Where request is an interface, which has serialize()

type request interface {
    serialize() ([]byte, error)
}

Then you can implement serialize() for every request type, and initialize message like this:

func (factory *HandlerFactory) Cancel() http.Handler {
    create := func() *message { return &message{&cancelRequest{}, auth{}} }
    return factory.defaultChain(createNewMessage, nil)
}