如何在Go中为这些类型建模

I have multiple types like this:

type QueryMessage struct {
    Header MessageHeader
    Type   MessageType
    Query  SqlQuery
}

type UpdateMessage struct {
    Header  MessageHeader
    Type    MessageType
    OldData map[string]interface{}
    NewData map[string]interface{}
}

type InsertMessage struct {
    Header MessageHeader
    Type   MessageType
    Data   map[string]interface{}
}

They all have two properties in common, Header and Type. In the end I need to aggregate them into an array of generic messages. At the moment my Message interface looks like this:

type Message interface {}

So what I basically do is something like this (casting them all to Message interface):

q := QueryMessage{ ... }
u := UpdateMessage{ ... }
i := InsertMessage{ ... }
allMessages := [3]Message { Message(q), Message(u), Message(i), }

This works, but it loses all the type information and I would like to be able to still expose Header and Type from the Message type (so that client code theoretically could cast the Message based on the Type back to it's original type.

How can this be done? I couldn't figure out a proper way, interfaces can't have properties and if I make Message a struct, Go doesn't allow me to cast e. g. a QueryMessage to a Message anymore.

Your interface can provide accessors :

type Message interface {
   GetHeader() MessageHeader
   GetType() MessageType
}

You then have to implement this interface on all your types.

To factor out the common part, you can use an extra base type, and embed it in your other structs :

// the interface :
type Message interface {
    GetHeader() MessageHeader
    GetType() MessageType
}

// a base struct type, which holds 2 fields and implements the Message interface :
type baseMessage struct {
    Header MessageHeader
    Type   MessageType
}

func (b *baseMessage) GetHeader() MessageHeader {
    return b.Header
}

func (b *baseMessage) GetType() MessageType {
    return b.Type
}

// your three types, with an embedded "baseMessage" part :
type QueryMessage struct {
    baseMessage
    Query SqlQuery
}

type UpdateMessage struct {
    baseMessage
    OldData map[string]interface{}
    NewData map[string]interface{}
}

type InsertMessage struct {
    baseMessage
    Data map[string]interface{}
}

// compile time check : all the above types implement the Message interface :
var _ Message = &QueryMessage{}
var _ Message = &UpdateMessage{}
var _ Message = &InsertMessage{}

https://play.golang.org/p/Uho_2loXpZ

Just an opinion, but considering the fact that Header and Type are just fields/data and not methods/behaviour, I'd lose the Message interface and instead use a Message struct.

type Message struct {
    Header  MessageHeader
    Type    MessageType
    Details interface{}
}

And then based on the value of the Type field you can cast Details to whatever.

if m.Type == QueryMessageType {
     q := m.Details.(SqlQuery)
} else if m.Type == UpdateMessageType {
     u := m.Details.(UpdateMessageDetails)
}

Or just use a type switch

switch m.Details.(type) {
case SqlQuery:
     // ...
case UpdateMessageDetails:
     // ...
}