Enums in Go
Go doesn’t have built-in enums, but you get enum-like behavior with typed constants and iota.
Core ideas
- Use a custom type plus a const block with
iota - Implement
String()for readable printing - Validate inputs via switch or helper functions
- Optionally implement
encoding.TextMarshaler/TextUnmarshalerfor JSON/text I/O
Basic enum-like pattern
package main
import "fmt"
type Status int
const (
StatusPending Status = iota
StatusRunning
StatusCompleted
StatusFailed
)
func (s Status) String() string {
switch s {
case StatusPending:
return "Pending"
case StatusRunning:
return "Running"
case StatusCompleted:
return "Completed"
case StatusFailed:
return "Failed"
default:
return "Unknown"
}
}
func main() {
var s Status = StatusRunning
fmt.Println(s, s.String()) // 1 Running
}
Starting from 1 or custom offsets
package main
// Roles start at 1
type Role int
const (
RoleUser Role = iota + 1 // 1
RoleModerator // 2
RoleAdmin // 3
)
Bit flags (advanced)
package main
// Use bit shifts for combinable flags
type Perm uint8
const (
PermRead Perm = 1 << iota // 0001
PermWrite // 0010
PermExec // 0100
)
func Has(p, flag Perm) bool { return p&flag != 0 }
Tips:
- Keep flags small (uint8/uint16) unless you need many bits
- Provide combine helpers and masks for clarity
Validating values
package main
import "fmt"
func IsValidStatus(s Status) bool {
switch s {
case StatusPending, StatusRunning, StatusCompleted, StatusFailed:
return true
default:
return false
}
}
func main() {
fmt.Println(IsValidStatus(Status(99))) // false
}
Marshaling to/from text/JSON
func (s Status) MarshalText() ([]byte, error) { return []byte(s.String()), nil }
func (s *Status) UnmarshalText(b []byte) error {
switch string(b) {
case "Pending": *s = StatusPending
case "Running": *s = StatusRunning
case "Completed": *s = StatusCompleted
case "Failed": *s = StatusFailed
default: return fmt.Errorf("invalid status: %q", b)
}
return nil
}
Best practices
- Prefer typed constants over untyped to prevent mixing domains (e.g.,
StatusvsPriority) - Group constants in a block; keep order stable to avoid shifting values
- Add
String()methods for debugging, logs, and UX - Use bit flags only when you need combinable options; otherwise simple enums are clearer
- Consider
stringertool (golang.org/x/tools/cmd/stringer) to generateString()and parsing code
Summary
- Enums in Go = typed constants +
iota - Provide
String()and validation helpers for robustness