# README
⚙️ Go Enum
Elegant, powerful, and dependency-free enums for Go with zero code generation!
[!TIP] This is just a ⚡ quick tutorial for general use cases. See more advanced features at the documentation.
🔧 Installation
go get -u github.com/xybor-x/enum
⚡ Quick start
Define enums
package main
import "github.com/xybor-x/enum"
type role any
type Role = enum.WrapEnum[role]
const (
RoleUser Role = iota
RoleAdmin
)
func init() {
enum.Map(RoleUser, "user")
enum.Map(RoleAdmin, "admin")
enum.Finalize[Role]()
}
[!CAUTION] Enum definitions are not thread-safe. Therefore, they should be finalized during initialization (at the global scope).
Usage
package main
import (
"encoding/json"
"fmt"
)
type User struct {
Role Role `json:"role"`
}
func main() {
// Print out the string representation of enum.
fmt.Println(RoleAdmin) // Output: admin
// Serialize a user to json.
user := User{Role: RoleUser}
data, _ := json.Marshal(user)
fmt.Println(string(data)) // Output: {"role": "user"}
}
Nullable fields
package main
import (
"encoding/json"
"fmt"
)
// NullRole is similar to sql.NullXXX, designed to handle nullable SQL and JSON fields.
type NullRole = enum.Nullable[Role]
type User struct {
Role NullRole `json:"role"`
}
func main() {
// Serialize a nullable role with a non-null value.
user := User{Role: NullRole{Enum: RoleUser, Valid: true}}
data, _ := json.Marshal(user)
fmt.Println(string(data)) // Output: {"role": "user"}
// Serialize a nullable role with a null value.
data, _ = json.Marshal(User{})
fmt.Println(string(data)) // Output: {"role": null}
}
Integrate with protobuf
Refer to the Integration Guide for details.
Suppose we have a protobuf enum defined as follows:
// Code generated by protoc-gen-go.
package proto
type Role int32
const (
Role_User Role = 0
Role_Admin Role = 1
)
...
We can integrate them into xybor-x/enum
. Here's an example:
package main
import (
"path/to/proto"
"github.com/xybor-x/enum"
)
type Role = enum.WrapEnum[proto.Role]
const (
RoleUser Role = iota
RoleAdmin
)
func init() {
// Map the enum to protobuf enum value.
enum.Map(RoleUser, proto.Role_User)
enum.Map(RoleAdmin, proto.Role_Admin)
enum.Finalize[Role]()
}
func main() {
// Convert from the protobuf enum to the Role enum.
role, ok := enum.From[Role](proto.Role_User)
// ok == true && role == RoleUser
// Convert from the Role enum to the protobuf enum.
role = RoleAdmin.To()
// role == proto.Role_Admin
// The string representation of these enums is inherited from proto.Role.
fmt.Println(RoleUser) // Output: User
}
📈 Performance
While it's true that the xybor-x/enum
approach will generally be slower than the code generation approaches, I still want to highlight the difference.
The benchmark results are based on defining an enum with 10 values at bench.
Code generation | xybor-x/enum | |
---|---|---|
ToString | 6 ns | 17 ns |
FromString | 15 ns | 22 ns |
json.Marshal | 113 ns | 148 ns |
json.Unmarshal | 147 ns | 144 ns |
SQL Value | 29 ns | 38 ns |
SQL Scan (bytes) | 29 ns | 41 ns |
SQL Scan (string) | 15 ns | 22 ns |
# Functions
All returns a slice containing all enum values of a specific type.
Finalize prevents the creation of any new enum values for the current type.
From returns the corresponding enum for a given representation, and whether it is valid.
FromInt returns the corresponding enum for a given int representation, and whether it is valid.
FromNumber returns the corresponding enum for a given number representation, and whether it is valid.
FromString returns the corresponding enum for a given string representation, and whether it is valid.
IsValid checks if an enum value is valid.
Map associates an enum with its representations under strict rules: - String enums map to themselves as the string representation; Stringer is also treated as a string representation if no string repr is found.
MarshalJSON serializes an enum value into its string representation.
MarshalXML converts enum to its string representation.
MarshalYAML serializes an enum value into its string representation.
MustFrom returns the corresponding enum for a given representation.
MustFromInt returns the corresponding enum for a given int representation.
MustFromNumber returns the corresponding enum for a given number representation.
MustFromString returns the corresponding enum for a given string representation.
MustTo returns the representation (the type is relied on P type parameter) for the given enum value.
NameOf returns the name of the enum type.
New creates a dynamic enum value then mapped to its representations.
NewExtended initializes an extended enum then mapped to its representations.
ScanSQL deserializes a database value into an enum type.
To returns the representation (the type is relied on P type parameter) for the given enum value.
ToInt returns the int representation for the given enum value.
ToString returns the string representation of the given enum value.
TrueNameOf returns the name of the enum type.
UnmarshalJSON deserializes a string representation of an enum value from JSON.
UnmarshalXML parses the string representation back into an enum.
UnmarshalYAML deserializes a string representation of an enum value from YAML.
ValueSQL serializes an enum into a database-compatible format.
# Type aliases
WrapEnum provides a set of built-in methods to simplify working with int enums.
WrapFloatEnum provides a set of built-in methods to simplify working with float64 enums.
WrapUintEnum provides a set of built-in methods to simplify working with uint enums.