Usage
Using goenums involves a simple workflow:
- Define your enum constants as you normally would with Go’s
iota - Add a
go:generatedirective to invoke goenums - Run
go generateto create the enum implementation - Use the generated code in your project
$ goenums -h
____ _____ ___ ____ __ ______ ___ _____
/ __ '/ __ \/ _ \/ __ \/ / / / __ '__ \/ ___/
/ /_/ / /_/ / __/ / / / /_/ / / / / / (__ )
\__, /\____/\___/_/ /_/\__,_/_/ /_/ /_/____/
/____/
Usage: goenums [options] file.go[,file2.go,...]
Options:
-c
-constraints
Generate local numeric constraints instead of importing golang.org/x/exp/constraints (default: true)
-x-exp-constraints
Import golang.org/x/exp/constraints instead of generating local numeric constraints (default: false)
-f
-failfast
Enable failfast mode - fail on generation of invalid enum while parsing (default: false)
-h
-help
Print help information
-i
-insensitive
Generate case insensitive string parsing (default: false)
-interfaces string
Generate only the listed interface handlers: json,text,yaml,sql,binary (default: all)
-l
-legacy
Generate legacy code without Go 1.23+ iterator support (default: false)
-legacy-text
Generate legacy quoted MarshalText output (default: false)
-o string
-output string
Specify the output format (default: go)
-v
-version
Print version information
-vv
-verbose
Enable verbose mode - prints out the generated code (default: false)
For users upgrading existing generated enums, see Migrating to goenums v0.6, including the -legacy-text compatibility option.
Adding a go:generate Directive
To use goenums, add a go:generate directive to your Go source file:
package validation
type status int
//go:generate goenums status.go
const (
unknown status = iota // invalid Unknown
pending // Pending
approved // Approved
rejected // Rejected
completed // Completed
)
Running Code Generation
To generate the enum implementations, run the following command:
$ go generate ./...
This will create the enum implementations in the same directory as the source file.
Selecting generated interfaces
By default, goenums generates JSON, Text, YAML, SQL, and Binary interface methods. Use --interfaces to generate only specific interface implementations:
goenums --interfaces=json,sql status.go
Valid values are json, text, yaml, sql, and binary. If the flag is omitted, all interfaces are generated.
-legacy-text only affects generated Text handlers. If text is not selected, -legacy-text has no generated-code effect.
What Gets Generated
goenums will create a new file alongside your enum definition, named after the type. For example, a status type will generate a statuses_enums.go file in the same directory.
This file will contain:
- A type-safe wrapper struct around your enum
- A singleton container with all valid enum values
- String conversion methods
- Parsing functions for various input types (including numeric types)
- JSON marshaling/unmarshaling
- YAML marshaling/unmarshaling
- Database scanning/valuing
- Binary marshaling/unmarshaling
- Text marshaling/unmarshaling
- Validation functions
- Iteration helpers
- Compile-time validation
- Compile-time exhaustiveness (Matcher interface, Match/MustMatch functions)
Using the Generated Code
After generating the enum implementations, you can use the generated code in your Go project.
// Import the package containing your enum
import "yourpackage/validation"
// Access enum values via the container
status := validation.Statuses.PASSED
// Convert to string
statusName := status.String() // "PASSED"
// Parse from string
parsed := validation.ParseStatus("FAILED")
// Check validity
if !parsed.IsValid() {
// Handle invalid status
}
// JSON marshaling/unmarshaling
type Task struct {
ID int `json:"id"`
Status validation.Status `json:"status"`
}
// Use in exhaustive function (great for tests)
validation.ExhaustiveStatuses(func(status validation.Status) {
// Process each status
switch status {
case validation.Statuses.PASSED:
// Handle passed
case validation.Statuses.FAILED:
// Handle failed
// ...handle other cases
}
})
// Iterate using modern Go 1.23+ range-over-func
for status := range validation.Statuses.All() {
fmt.Printf("Status: %s\n", status)
}
// Legacy iteration
for _, status := range validation.Statuses.All() {
fmt.Printf("Status: %s\n", status)
}
Compile-time Exhaustiveness
goenums generates a Matcher interface and Match/MustMatch functions for each enum. The interface has one method per valid enum value. That means the Go compiler can enforce exhaustive handling for any matcher type you pass to Match or MustMatch.
type statusHandler struct{}
func (statusHandler) Pending() {}
func (statusHandler) Approved() {}
func (statusHandler) Rejected() {}
func (statusHandler) Completed() {}
// Compile-time check: statusHandler must satisfy StatusMatcher.
// If a new enum value is added, this line fails to compile until the
// corresponding method is added to statusHandler.
var _ validation.StatusMatcher = statusHandler{}
func handleStatus(status validation.Status) error {
// Match returns an error if the matcher is nil or the enum value is not handled.
if err := validation.MatchStatus(status, statusHandler{}); err != nil {
return err
}
// MustMatch panics instead of returning an error.
validation.MustMatchStatus(status, statusHandler{})
return nil
}
This is different from ExhaustiveStatuses, which iterates over every valid value. MatchStatus dispatches one enum value to a handler method, while the StatusMatcher interface gives compile-time coverage when enum values are added, removed, or renamed.
Here is some more Examples →
Now you can use the generated status enums type in your code:
/// Access enum constants safely
myStatus := validation.Statuses.PASSED
// Convert to string
fmt.Println(myStatus.String()) // "PASSED"
// Parse from various sources
parsed, _ := validation.ParseStatus("SKIPPED")
// Validate enum values
if !parsed.IsValid() {
fmt.Println("Invalid status")
}
Basic Command Syntax
goenums [options] file.go[,file2.go,...]
Where
Adding a go:generate Directive
To use goenums, you need to add a go:generate directive to your Go source file.
package validation
type status int
//go:generate goenums status.go
const (
unknown status = iota // invalid
failed
passed
skipped
scheduled
running
booked
)
Running Code Generation
To generate the enum implementations, run the following command:
go generate ./...
This will create the enum implementations in the same directory as the source file.
What Gets Generated
goenums will create a new file alongside your enum definition, named after the type. For example, a status type will generate a statuses_enums.go file in the same directory.
This file will contain:
- A type-safe wrapper struct around your enum
- A singleton container with all valid enum values
- String conversion methods
- Parsing functions for various input types (including numeric types)
- JSON marshaling/unmarshaling
- YAML marshaling/unmarshaling
- Database scanning/valuing
- Binary marshaling/unmarshaling
- Text marshaling/unmarshaling
- Validation functions
- Iteration helpers
- Compile-time validation
- Compile-time exhaustiveness (Matcher interface, Match/MustMatch functions)
Using the Generated Code
After generating the enum implementations, you can use the generated code in your Go project.
// Import the package containing your enum
import "yourpackage/validation"
// Access enum values via the container
status := validation.Statuses.PASSED
// Convert to string
statusName := status.String() // "PASSED"
// Parse from string
parsed, err := validation.ParseStatus("FAILED")
if err != nil {
// Handle error
}
// Check validity
if !parsed.IsValid() {
// Handle invalid status
}
// JSON marshaling/unmarshaling
type Task struct {
ID int `json:"id"`
Status validation.Status `json:"status"`
}
// Use in exhaustive function (great for tests)
validation.ExhaustiveStatuses(func(status validation.Status) {
// Process each status
switch status {
case validation.Statuses.PASSED:
// Handle passed
case validation.Statuses.FAILED:
// Handle failed
// ...handle other cases
}
})
// Iterate using modern Go 1.23+ range-over-func
for status := range validation.Statuses.All() {
fmt.Printf("Status: %s\n", status)
}
Here is some more Examples →