Go语言通过常量和自定义类型模拟Java枚举功能。在GoZero中,可使用常量组+iota实现基础枚举,为枚举类型添加String()方法获取字符串表示,并支持复杂结构和方法。在模型层存储枚举值,逻辑层进行状态验证,API层转换状态文本。还可实现枚举验证器、自定义JSON序列化及工具函数,便于全项目统一使用枚举值,确保类型安全。
1. 基础枚举实现
1.1 使用常量组
// common/enums/user_status.go
package enums
type UserStatus int
const (
UserStatusNormal UserStatus = iota + 1 // 正常
UserStatusDisabled // 禁用
UserStatusDeleted // 删除
)
func (s UserStatus) String() string {
switch s {
case UserStatusNormal:
return "正常"
case UserStatusDisabled:
return "禁用"
case UserStatusDeleted:
return "删除"
default:
return "未知状态"
}
}
1.2 使用更复杂的枚举结构
// common/enums/order_type.go
package enums
type OrderType struct {
Code int
Name string
}
var (
OrderTypeNormal = OrderType{1, "普通订单"}
OrderTypeGroup = OrderType{2, "团购订单"}
OrderTypeFlash = OrderType{3, "秒杀订单"}
)
func (o OrderType) GetCode() int {
return o.Code
}
func (o OrderType) GetName() string {
return o.Name
}
2. 带方法的枚举实现
// common/enums/payment_method.go
package enums
type PaymentMethod int
const (
PaymentAlipay PaymentMethod = iota + 1
PaymentWechat
PaymentBank
)
func (p PaymentMethod) String() string {
return [...]string{"支付宝", "微信", "银行卡"}[p-1]
}
func (p PaymentMethod) Code() string {
return [...]string{"ALIPAY", "WECHAT", "BANK"}[p-1]
}
func (p PaymentMethod) IsOnline() bool {
return p == PaymentAlipay || p == PaymentWechat
}
// 通过code获取枚举
func FromCode(code string) (PaymentMethod, error) {
switch code {
case "ALIPAY":
return PaymentAlipay, nil
case "WECHAT":
return PaymentWechat, nil
case "BANK":
return PaymentBank, nil
default:
return 0, errors.New("未知的支付方式")
}
}
3. 在 GoZero 中的使用示例
3.1 在模型中使用
// model/user.go
package model
import (
"yourproject/common/enums"
"time"
)
type User struct {
Id int64 `db:"id"`
Name string `db:"name"`
Status int `db:"status"` // 使用枚举值存储
CreatedAt time.Time `db:"created_at"`
}
// 获取状态文本
func (u *User) GetStatusText() string {
return enums.UserStatus(u.Status).String()
}
3.2 在逻辑层使用
// internal/logic/userlogic.go
package logic
import (
"context"
"yourproject/common/enums"
"yourproject/common/errorx"
)
func (l *UserLogic) DisableUser(id int64) error {
user, err := l.svcCtx.UserModel.FindOne(l.ctx, id)
if err != nil {
return errorx.NewDefaultError("用户不存在")
}
if user.Status == int(enums.UserStatusDisabled) {
return errorx.NewCodeError(1001, "用户已禁用")
}
user.Status = int(enums.UserStatusDisabled)
err = l.svcCtx.UserModel.Update(l.ctx, user)
if err != nil {
return errorx.NewSysError("更新用户状态失败")
}
return nil
}
3.3 在API层使用
// types/user.go
package types
import "yourproject/common/enums"
type UserInfo struct {
Id int64 `json:"id"`
Name string `json:"name"`
Status int `json:"status"`
StatusText string `json:"statusText"` // 前端展示的文本
}
func (u *UserInfo) TransformStatusText() {
u.StatusText = enums.UserStatus(u.Status).String()
}
4. 枚举验证器
可以在请求参数验证中使用枚举:
// types/userreq.go
package types
import (
"yourproject/common/enums"
"github.com/zeromicro/go-zero/core/errorx"
)
type UpdateUserStatusReq struct {
Id int64 `json:"id"`
Status int `json:"status"`
}
func (req *UpdateUserStatusReq) Validate() error {
switch req.Status {
case int(enums.UserStatusNormal),
int(enums.UserStatusDisabled),
int(enums.UserStatusDeleted):
return nil
default:
return errorx.NewCodeError(1002, "无效的用户状态")
}
}
5. 枚举JSON序列化
如果需要自定义JSON序列化:
// common/enums/gender.go
package enums
import (
"encoding/json"
"fmt"
)
type Gender int
const (
GenderUnknown Gender = 0
GenderMale Gender = 1
GenderFemale Gender = 2
)
func (g Gender) String() string {
switch g {
case GenderMale:
return "男"
case GenderFemale:
return "女"
default:
return "未知"
}
}
// 自定义JSON序列化
func (g Gender) MarshalJSON() ([]byte, error) {
return json.Marshal(map[string]interface{}{
"code": int(g),
"name": g.String(),
})
}
// 自定义JSON反序列化
func (g *Gender) UnmarshalJSON(data []byte) error {
var code int
if err := json.Unmarshal(data, &code); err != nil {
return err
}
switch code {
case 0, 1, 2:
*g = Gender(code)
return nil
default:
return fmt.Errorf("无效的性别代码: %d", code)
}
}
6. 枚举工具函数
可以添加一些工具函数:
// common/enums/enumutil.go
package enums
// 获取所有用户状态
func GetAllUserStatus() []map[string]interface{} {
return []map[string]interface{}{
{"code": UserStatusNormal, "name": UserStatusNormal.String()},
{"code": UserStatusDisabled, "name": UserStatusDisabled.String()},
{"code": UserStatusDeleted, "name": UserStatusDeleted.String()},
}
}
// 检查用户状态是否有效
func IsValidUserStatus(status int) bool {
switch status {
case int(UserStatusNormal),
int(UserStatusDisabled),
int(UserStatusDeleted):
return true
default:
return false
}
}
7. 在GoZero API中使用枚举
// api/user.go
package main
import (
"net/http"
"yourproject/common/enums"
"yourproject/internal/svc"
"yourproject/internal/types"
"github.com/zeromicro/go-zero/rest/httpx"
)
func getUserStatusHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// 返回所有用户状态枚举
httpx.OkJson(w, enums.GetAllUserStatus())
}
}
总结
在GoZero中实现类似Java枚举的功能可以通过以下方式:
-
使用
iota
创建基础枚举 -
为枚举类型添加
String()
方法实现字符串表示 -
添加验证方法确保枚举值有效
-
实现自定义JSON序列化和反序列化
-
在模型、逻辑层和API层中统一使用枚举
-
提供工具函数方便枚举操作