What's an idiomatic way in Go to superclass similar (but not identical) data types in order to minimize code duplication? Trite example:
import "time"
type LinuxUtmp struct {
ut_type uint16
_ [2]byte
ut_pid uint32
ut_line [32]byte
ut_id [4]byte
ut_user [32]byte
ut_host [256]byte
exit_status [2]uint32
tv_sec uint32
tv_usec uint32
...
}
func (l LinuxUtmp) User() string {
return string(l.ut_user[:])
}
func (l LinuxUtmp) Time() time.Time {
return time.Unix(int64(l.tv_sec), int64(l.tv_usec))
}
type BsdUtmp struct {
ut_line [8]char
ut_name [16]char
ut_host [16]char
ut_time uint32
}
func (b BsdUtmp) User() string {
return string(b.ut_user[:])
}
func (b BsdUtmp) Time() time.Time {
return time.Unix(int64(b.ut_time), 0)
}
Obviously there's more to it than that, but I'd love to be able to somehow superclass those so I only have to write and maintain one copy of particular functions. An interface seems to be the "right" way, but that leaves much to be desired (non-working example):
type Utmp interface {
Time() time.Time
}
func User(u Utmp) string {
return string(u.ut_user[:])
}
I've also considered embedding, but that seems a dead end too since Go is so strictly typed. Am I doomed to have multiple pieces of code that are identical in every way but the signature?
[edit]
Part of the complication is that I'm using encoding/binary.Read() to parse this data according to endianness (it's not just utmp records and not just Linux/BSD). To use that, the fields must be [exported] in the struct in the precise order they are on-disk. Hence I can't just embed the fields of another struct, as in some records they're in different order (and of differing sizes)