Enum Stringer Interface optimisation in Go
The most idiomatic way of describing an enum type in Go is to use constants, often in conjunction with .
A pattern I’ve used to implement the Stringer
interface for an enum type is to
lookup the string representation in a slice. Consider this snippet from a
project I’m working on:
// Status ...
type Status uint32
// List of possible status values
const (
// The operation is known, but hasn't been decided yet
Processing Status = iota
// The operation will never be accepted
Rejected
// The operation was accepted
Accepted
...
)
func (s Status) String() string {
return []string{"processing", "rejected", "accepted"}[s]
}
The snippet above works correct but has a few glitches – passing
Status(-2)
or Status(300)
will cause the String()
method to panic, and
when appending to the slice, the order of the enum constants has to be taken
into consideration.
A way to optimise this is to use a map which provides O(1)
access time rather
than the linear O(n)
time in the string slice version.
...
// Map of Status values back to their constant names for pretty printing.
var txStatuses = map[Status]string{
Processing: "processing",
Rejected: "rejected",
Accepted: "accepted",
}
// String returns the ErrorCode as a human-readable name.
func (s Status) String() string {
if s := txStatuses[s]; s != "" {
return s
}
return fmt.Sprintf("Unknown Status (%d)", uint32(s))
}