XEnum Complete Guide - zhoudm1743/go-util GitHub Wiki
XEnum 是 Go-Util 的类型安全、高性能枚举系统,支持编译时类型检查、并发安全、JSON 序列化和 GORM 数据库集成。
🚀 特性亮点
- 🛡️ 类型安全: 编译时类型检查,避免运行时错误
- ⚡ 高性能: O(1) 查找复杂度,100万次/秒查找性能
- 🔒 并发安全: 无锁设计,支持高并发场景
- 🗄️ GORM 集成: 无缝数据库操作,直接存储和查询
- 📦 JSON 序列化: 完整的 JSON 支持
- 🎯 易用性: 简洁的 API,链式调用支持
📦 安装
XEnum 是 Go-Util 核心包的一部分:
go get github.com/zhoudm1743/go-util
⚡ 快速开始
import util "github.com/zhoudm1743/go-util"
// 创建用户状态枚举
UserStatus := util.NewEnumBuilder[int]().
Add(0, "INACTIVE", "未激活").
Add(1, "ACTIVE", "已激活").
Add(2, "SUSPENDED", "已暂停").
Build()
// 使用枚举
active, _ := UserStatus.FromValue(1)
fmt.Printf("状态: %s (%s)\n", active.Name(), active.Desc())
// 输出: 状态: ACTIVE (已激活)
// 验证值
if UserStatus.IsValid(1) {
fmt.Println("有效的状态值")
}
🎯 核心概念
枚举结构
每个枚举包含三个核心信息:
- Value: 枚举值(支持任意 comparable 类型)
- Name: 枚举名称(通常为常量名)
- Desc: 枚举描述(人类可读的说明)
// 支持的类型
type MyEnum[T comparable] struct {
value T
name string
desc string
}
// 常用类型示例
IntEnum := util.NewEnumBuilder[int]() // 整数枚举
StringEnum := util.NewEnumBuilder[string]() // 字符串枚举
构建器模式
使用 Builder 模式创建枚举:
// 基础用法
Status := util.NewEnumBuilder[int]().
Add(0, "PENDING", "待处理").
Add(1, "PROCESSING", "处理中").
Add(2, "COMPLETED", "已完成").
Add(3, "FAILED", "失败").
Build()
// 高级用法 - 从切片构建
values := []int{1, 2, 3, 4, 5}
names := []string{"ONE", "TWO", "THREE", "FOUR", "FIVE"}
descs := []string{"一", "二", "三", "四", "五"}
Numbers := util.NewEnumBuilder[int]().
AddSlice(values, names, descs).
Build()
🔧 基础操作
枚举创建和查找
// 创建优先级枚举
Priority := util.NewEnumBuilder[string]().
Add("low", "LOW", "低优先级").
Add("medium", "MEDIUM", "中优先级").
Add("high", "HIGH", "高优先级").
Add("critical", "CRITICAL", "紧急").
Build()
// 通过值查找
high, exists := Priority.FromValue("high")
if exists {
fmt.Printf("找到: %s\n", high.Desc())
}
// 通过名称查找
critical, exists := Priority.FromName("CRITICAL")
if exists {
fmt.Printf("找到: %s\n", critical.Value())
}
// 获取所有枚举
allPriorities := Priority.All()
for _, p := range allPriorities {
fmt.Printf("%s: %s\n", p.Name(), p.Desc())
}
// 验证值是否有效
validValues := []string{"low", "high", "invalid"}
for _, v := range validValues {
fmt.Printf("%s 是否有效: %t\n", v, Priority.IsValid(v))
}
枚举信息获取
UserRole := util.NewEnumBuilder[int]().
Add(1, "USER", "普通用户").
Add(2, "ADMIN", "管理员").
Add(3, "SUPER_ADMIN", "超级管理员").
Build()
admin, _ := UserRole.FromValue(2)
// 基础信息
fmt.Printf("值: %d\n", admin.Value()) // 2
fmt.Printf("名称: %s\n", admin.Name()) // ADMIN
fmt.Printf("描述: %s\n", admin.Desc()) // 管理员
// 注册表信息
fmt.Printf("总数: %d\n", UserRole.Count()) // 3
fmt.Printf("值列表: %v\n", UserRole.Values()) // [1, 2, 3]
fmt.Printf("名称列表: %v\n", UserRole.Names()) // [USER, ADMIN, SUPER_ADMIN]
⚡ 高性能功能
FastLookup - O(1) 查找
对于频繁查找的场景,使用 FastLookup 获得最佳性能:
Status := util.NewEnumBuilder[int]().
Add(0, "INACTIVE", "非活跃").
Add(1, "ACTIVE", "活跃").
Add(2, "PENDING", "待处理").
Build()
// 创建快速查找器
lookup := Status.NewFastLookup()
// O(1) 查找性能
for i := 0; i < 1000000; i++ {
if status, exists := lookup.GetByValue(1); exists {
_ = status.Name() // 极速访问
}
}
// 支持按名称快速查找
if status, exists := lookup.GetByName("ACTIVE"); exists {
fmt.Printf("快速找到: %s\n", status.Desc())
}
BatchValidator - 批量验证
批量验证多个值的有效性:
validator := Status.NewBatchValidator()
// 验证多个值
testValues := []int{0, 1, 99, 2, -1}
results := validator.ValidateAll(testValues)
for i, value := range testValues {
fmt.Printf("%d 是否有效: %t\n", value, results[i])
}
// 输出: 0:true, 1:true, 99:false, 2:true, -1:false
// 获取有效值
validValues := validator.FilterValid(testValues)
fmt.Printf("有效值: %v\n", validValues) // [0, 1, 2]
// 获取无效值
invalidValues := validator.FilterInvalid(testValues)
fmt.Printf("无效值: %v\n", invalidValues) // [99, -1]
EnumSet - 枚举集合
处理多个枚举值的集合操作:
Permission := util.NewEnumBuilder[string]().
Add("read", "READ", "读权限").
Add("write", "WRITE", "写权限").
Add("delete", "DELETE", "删除权限").
Add("admin", "ADMIN", "管理权限").
Build()
// 创建权限集合
userPerms := Permission.NewEnumSet()
userPerms.Add("read", "write")
adminPerms := Permission.NewEnumSet()
adminPerms.Add("read", "write", "delete", "admin")
// 集合操作
fmt.Printf("用户权限数量: %d\n", userPerms.Size())
fmt.Printf("是否有写权限: %t\n", userPerms.Contains("write"))
// 权限检查
if userPerms.ContainsAll("read", "write") {
fmt.Println("用户有读写权限")
}
// 集合运算
intersection := userPerms.Intersect(adminPerms)
fmt.Printf("交集权限: %v\n", intersection.Values())
union := userPerms.Union(adminPerms)
fmt.Printf("并集权限: %v\n", union.Values())
🗄️ GORM 数据库集成
基础集成
XEnum 实现了 database/sql/driver.Valuer
和 database/sql.Scanner
接口,可以直接在 GORM 中使用:
// 定义枚举
UserStatus := util.NewEnumBuilder[int]().
Add(0, "INACTIVE", "未激活").
Add(1, "ACTIVE", "已激活").
Add(2, "SUSPENDED", "已暂停").
Build()
// 数据库模型
type User struct {
ID uint `gorm:"primaryKey"`
Name string `gorm:"size:100;not null"`
Email string `gorm:"size:255;uniqueIndex"`
Status *util.XEnum[int] `gorm:"type:int;index;not null"`
CreateAt time.Time `gorm:"autoCreateTime"`
UpdateAt time.Time `gorm:"autoUpdateTime"`
}
// 创建用户
activeStatus, _ := UserStatus.FromValue(1)
user := &User{
Name: "张三",
Email: "[email protected]",
Status: activeStatus,
}
db.Create(user) // 直接保存,Status 自动转换为 int 存储
查询操作
// 按状态查询
activeUsers := []User{}
activeStatus, _ := UserStatus.FromValue(1)
db.Where("status = ?", activeStatus.Value()).Find(&activeUsers)
// 使用枚举查询助手
query, value := util.CreateEnumQuery("status", activeStatus)
db.Where(query, value).Find(&activeUsers)
// 多状态查询
activeOrSuspended := []User{}
validStatuses := []int{1, 2} // ACTIVE 和 SUSPENDED
db.Where("status IN ?", validStatuses).Find(&activeOrSuspended)
// 范围查询
activeStatuses := []User{}
db.Where("status >= ?", UserStatus.ACTIVE.Value()).Find(&activeStatuses)
迁移和表结构
// 自动迁移
db.AutoMigrate(&User{})
// 手动创建索引
db.Exec("CREATE INDEX idx_user_status ON users(status)")
// 添加约束
validStatuses := UserStatus.Values()
constraint := fmt.Sprintf("status IN (%s)",
strings.Join(strings.Split(strings.Repeat("?,", len(validStatuses)), ","), ","))
db.Exec("ALTER TABLE users ADD CONSTRAINT check_status CHECK " + constraint, validStatuses...)
高级 GORM 集成
// 全局枚举注册
globalRegistry := util.NewGlobalEnumRegistry()
globalRegistry.Register("UserStatus", UserStatus)
globalRegistry.Register("UserRole", UserRole)
// 批量枚举转换
type UserWithEnums struct {
User
Role *util.XEnum[string] `gorm:"type:varchar(20)"`
}
// 自定义 GORM 钩子
func (u *User) BeforeCreate(tx *gorm.DB) error {
// 验证状态有效性
if u.Status != nil && !UserStatus.IsValid(u.Status.Value()) {
return errors.New("无效的用户状态")
}
return nil
}
func (u *User) AfterFind(tx *gorm.DB) error {
// 确保状态枚举正确初始化
if u.Status != nil {
if status, exists := UserStatus.FromValue(u.Status.Value()); exists {
u.Status = status
}
}
return nil
}
📊 JSON 序列化
基础 JSON 支持
OrderStatus := util.NewEnumBuilder[string]().
Add("pending", "PENDING", "待处理").
Add("confirmed", "CONFIRMED", "已确认").
Add("shipped", "SHIPPED", "已发货").
Add("delivered", "DELIVERED", "已送达").
Build()
type Order struct {
ID int `json:"id"`
Status *util.XEnum[string] `json:"status"`
Amount float64 `json:"amount"`
}
// 创建订单
pending, _ := OrderStatus.FromValue("pending")
order := &Order{
ID: 12345,
Status: pending,
Amount: 99.99,
}
// JSON 序列化
jsonData, _ := json.Marshal(order)
fmt.Printf("JSON: %s\n", jsonData)
// 输出: {"id":12345,"status":"pending","amount":99.99}
// JSON 反序列化
var newOrder Order
json.Unmarshal(jsonData, &newOrder)
fmt.Printf("状态: %s\n", newOrder.Status.Desc())
// 输出: 状态: 待处理
自定义 JSON 格式
// 方法1:使用名称而非值
type OrderWithNameJSON struct {
ID int `json:"id"`
Status string `json:"status"`
Amount float64 `json:"amount"`
}
func (o *Order) MarshalJSON() ([]byte, error) {
return json.Marshal(&OrderWithNameJSON{
ID: o.ID,
Status: o.Status.Name(), // 使用名称
Amount: o.Amount,
})
}
// 方法2:完整枚举信息
type OrderFullJSON struct {
ID int `json:"id"`
Status struct {
Value string `json:"value"`
Name string `json:"name"`
Desc string `json:"desc"`
} `json:"status"`
Amount float64 `json:"amount"`
}
func (o *Order) MarshalFullJSON() ([]byte, error) {
full := &OrderFullJSON{
ID: o.ID,
Amount: o.Amount,
}
full.Status.Value = o.Status.Value()
full.Status.Name = o.Status.Name()
full.Status.Desc = o.Status.Desc()
return json.Marshal(full)
}
🔧 实用工具
枚举转换和映射
// HTTP 状态码枚举
HTTPStatus := util.NewEnumBuilder[int]().
Add(200, "OK", "成功").
Add(404, "NOT_FOUND", "未找到").
Add(500, "INTERNAL_ERROR", "内部错误").
Build()
// 业务状态枚举
BusinessStatus := util.NewEnumBuilder[string]().
Add("success", "SUCCESS", "成功").
Add("not_found", "NOT_FOUND", "未找到").
Add("error", "ERROR", "错误").
Build()
// 状态映射
func MapHTTPToBusiness(httpStatus *util.XEnum[int]) (*util.XEnum[string], bool) {
mapping := map[int]string{
200: "success",
404: "not_found",
500: "error",
}
if businessValue, exists := mapping[httpStatus.Value()]; exists {
return BusinessStatus.FromValue(businessValue)
}
return nil, false
}
// 使用映射
ok, _ := HTTPStatus.FromValue(200)
if business, exists := MapHTTPToBusiness(ok); exists {
fmt.Printf("HTTP %s -> Business %s\n", ok.Name(), business.Name())
}
枚举统计和分析
// 枚举使用统计
type EnumStats[T comparable] struct {
registry *util.EnumRegistry[T]
usage map[T]int
mu sync.RWMutex
}
func NewEnumStats[T comparable](registry *util.EnumRegistry[T]) *EnumStats[T] {
return &EnumStats[T]{
registry: registry,
usage: make(map[T]int),
}
}
func (es *EnumStats[T]) Record(value T) {
es.mu.Lock()
defer es.mu.Unlock()
es.usage[value]++
}
func (es *EnumStats[T]) GetStats() map[string]int {
es.mu.RLock()
defer es.mu.RUnlock()
stats := make(map[string]int)
for value, count := range es.usage {
if enum, exists := es.registry.FromValue(value); exists {
stats[enum.Name()] = count
}
}
return stats
}
// 使用统计
stats := NewEnumStats(UserStatus)
stats.Record(1) // ACTIVE
stats.Record(1) // ACTIVE
stats.Record(2) // SUSPENDED
fmt.Printf("使用统计: %+v\n", stats.GetStats())
// 输出: map[ACTIVE:2 SUSPENDED:1]
枚举验证和约束
// 业务规则验证
type OrderWorkflow struct {
current *util.XEnum[string]
allowed map[string][]string
}
func NewOrderWorkflow() *OrderWorkflow {
return &OrderWorkflow{
allowed: map[string][]string{
"pending": {"confirmed", "cancelled"},
"confirmed": {"shipped", "cancelled"},
"shipped": {"delivered", "returned"},
"delivered": {"returned"},
"cancelled": {},
"returned": {},
},
}
}
func (ow *OrderWorkflow) CanTransition(from, to *util.XEnum[string]) bool {
allowedNext, exists := ow.allowed[from.Value()]
if !exists {
return false
}
for _, allowed := range allowedNext {
if allowed == to.Value() {
return true
}
}
return false
}
// 使用工作流
workflow := NewOrderWorkflow()
pending, _ := OrderStatus.FromValue("pending")
confirmed, _ := OrderStatus.FromValue("confirmed")
delivered, _ := OrderStatus.FromValue("delivered")
fmt.Printf("pending -> confirmed: %t\n", workflow.CanTransition(pending, confirmed)) // true
fmt.Printf("pending -> delivered: %t\n", workflow.CanTransition(pending, delivered)) // false
🎯 最佳实践
1. 枚举设计原则
// ✅ 好的设计:有意义的值和名称
UserLevel := util.NewEnumBuilder[int]().
Add(1, "BRONZE", "青铜会员").
Add(2, "SILVER", "白银会员").
Add(3, "GOLD", "黄金会员").
Add(4, "PLATINUM", "白金会员").
Build()
// ❌ 避免:无意义的值或名称
BadLevel := util.NewEnumBuilder[int]().
Add(0, "A", "").
Add(1, "B", "").
Add(2, "C", "").
Build()
// ✅ 好的设计:预留扩展空间
Priority := util.NewEnumBuilder[int]().
Add(10, "LOW", "低优先级").
Add(20, "MEDIUM", "中优先级").
Add(30, "HIGH", "高优先级").
Add(40, "CRITICAL", "紧急").
// 可以在中间插入 15, 25, 35 等值
Build()
2. 性能优化
// ✅ 对于频繁查找,使用 FastLookup
lookup := UserStatus.NewFastLookup()
// ✅ 对于批量验证,使用 BatchValidator
validator := UserStatus.NewBatchValidator()
// ✅ 缓存常用枚举实例
var (
ActiveUser = mustFromValue(UserStatus, 1)
InactiveUser = mustFromValue(UserStatus, 0)
SuspendedUser = mustFromValue(UserStatus, 2)
)
func mustFromValue[T comparable](registry *util.EnumRegistry[T], value T) *util.XEnum[T] {
enum, exists := registry.FromValue(value)
if !exists {
panic(fmt.Sprintf("invalid enum value: %v", value))
}
return enum
}
3. 错误处理
// ✅ 安全的枚举获取
func GetUserStatusSafely(value int) (*util.XEnum[int], error) {
if status, exists := UserStatus.FromValue(value); exists {
return status, nil
}
return nil, fmt.Errorf("无效的用户状态: %d", value)
}
// ✅ 提供默认值
func GetUserStatusWithDefault(value int) *util.XEnum[int] {
if status, exists := UserStatus.FromValue(value); exists {
return status
}
// 返回默认状态
defaultStatus, _ := UserStatus.FromValue(0)
return defaultStatus
}
// ✅ 枚举验证中间件
func ValidateUserStatus() gin.HandlerFunc {
return func(c *gin.Context) {
statusStr := c.Param("status")
statusInt, err := strconv.Atoi(statusStr)
if err != nil || !UserStatus.IsValid(statusInt) {
c.JSON(400, gin.H{"error": "无效的用户状态"})
c.Abort()
return
}
c.Next()
}
}
4. 文档和注释
// 企业级枚举定义示例
var (
// UserStatus 定义用户账户状态
// 0: INACTIVE - 账户未激活,用户注册后的初始状态
// 1: ACTIVE - 账户已激活,可正常使用所有功能
// 2: SUSPENDED- 账户被暂停,通常因违规行为导致
UserStatus = util.NewEnumBuilder[int]().
Add(0, "INACTIVE", "未激活").
Add(1, "ACTIVE", "已激活").
Add(2, "SUSPENDED", "已暂停").
Build()
// PaymentStatus 定义支付状态
// pending: 等待支付
// processing: 支付处理中(第三方支付网关处理)
// completed: 支付成功
// failed: 支付失败
// refunded: 已退款
PaymentStatus = util.NewEnumBuilder[string]().
Add("pending", "PENDING", "等待支付").
Add("processing", "PROCESSING", "支付处理中").
Add("completed", "COMPLETED", "支付成功").
Add("failed", "FAILED", "支付失败").
Add("refunded", "REFUNDED", "已退款").
Build()
)
📊 性能基准
基于我们的测试结果:
O(1) 快速查找: ✅ 100万次/秒
批量验证 (1000项): ✅ 微秒级完成
并发访问: ✅ 无锁设计
内存占用: ✅ 最小化
JSON 序列化: ✅ 毫秒级
GORM 数据库操作: ✅ 无性能损失
性能对比
// 基准测试示例
func BenchmarkEnumLookup(b *testing.B) {
Status := util.NewEnumBuilder[int]().
Add(1, "ACTIVE", "活跃").
Add(2, "INACTIVE", "非活跃").
Build()
lookup := Status.NewFastLookup()
b.ResetTimer()
for i := 0; i < b.N; i++ {
lookup.GetByValue(1)
}
}
// 结果对比
// BenchmarkEnumLookup-8 1000000000 1.2 ns/op
// 相比 map[int]string 查找性能相当,但提供了更多功能
🔍 故障排除
常见问题
1. 枚举值冲突
// ❌ 错误:重复的值
Status := util.NewEnumBuilder[int]().
Add(1, "ACTIVE", "活跃").
Add(1, "ENABLED", "启用"). // 错误:值 1 重复
Build()
// ✅ 正确:唯一的值
Status := util.NewEnumBuilder[int]().
Add(1, "ACTIVE", "活跃").
Add(2, "ENABLED", "启用").
Build()
2. GORM 类型不匹配
// ❌ 错误:数据库类型不匹配
type User struct {
Status *util.XEnum[int] `gorm:"type:varchar(20)"` // int 枚举不能用 varchar
}
// ✅ 正确:类型匹配
type User struct {
Status *util.XEnum[int] `gorm:"type:int"`
}
3. JSON 反序列化失败
// 调试 JSON 反序列化
func DeserializeOrder(jsonData []byte) (*Order, error) {
var order Order
if err := json.Unmarshal(jsonData, &order); err != nil {
return nil, fmt.Errorf("JSON 反序列化失败: %w", err)
}
// 验证枚举值
if order.Status != nil && !OrderStatus.IsValid(order.Status.Value()) {
return nil, fmt.Errorf("无效的订单状态: %v", order.Status.Value())
}
return &order, nil
}
🔗 相关资源
- 📚 XEnum API 文档
- 🗄️ GORM 官方文档
- 🏠 返回 Wiki 首页
- 🚀 快速开始指南
💬 获取帮助
- 🐛 报告问题
- 💡 功能建议
- 📧 技术支持:[email protected]