
go常量枚举
go没有这俩玩意,但是这俩玩意是真的好用啊,没有就自己实现一把。最佳实践!!!
常量
注意,这里显示了UnmarshalJSON
和MarshalJSON
这两个方法,是为了在json序列化Status
的时候,触发这两个函数,做出对应的逻辑判断。 其实可以忽略不写。解析成功在后面判断也行。
go
package main
import (
"encoding/json"
"fmt"
"log"
)
// 1. 枚举定义(你的代码)
type Status string
const (
StatusPending Status = "pending"
StatusApproved Status = "approved"
StatusRejected Status = "rejected"
)
var AllStatus = []Status{StatusPending, StatusApproved, StatusRejected}
func (s Status) IsValid() bool {
for _, v := range AllStatus {
if v == s {
return true
}
}
return false
}
func (s Status) String() string {
return string(s)
}
// JSON 支持(可选)
func (s Status) MarshalJSON() ([]byte, error) {
return json.Marshal(string(s))
}
func (s *Status) UnmarshalJSON(data []byte) error {
var str string
if err := json.Unmarshal(data, &str); err != nil {
return err
}
*s = Status(str)
if !s.IsValid() {
return fmt.Errorf("invalid status: %s", str)
}
return nil
}
// ========================================================================================
// 2. 订单结构体
type Order struct {
ID string `json:"id"`
Name string `json:"name"`
Status Status `json:"status"`
}
// 3. 创建新订单(默认状态:pending)
func NewOrder(id, name string) *Order {
return &Order{
ID: id,
Name: name,
Status: StatusPending,
}
}
// 4. 更新订单状态(带合法性校验)
func (o *Order) UpdateStatus(newStatus Status) error {
if !newStatus.IsValid() {
return fmt.Errorf("无效的订单状态: %s", newStatus)
}
o.Status = newStatus
return nil
}
// 5. 打印订单信息
func (o *Order) Print() {
fmt.Printf("📦 订单 ID: %s, 名称: %s, 状态: %s\n", o.ID, o.Name, o.Status)
}
func main() {
// === 1. 创建订单 ===
order := NewOrder("O1001", "iPhone 16")
order.Print() // 状态: pending
// === 2. 更新状态为 approved ===
err := order.UpdateStatus(StatusApproved)
if err != nil {
log.Fatal(err)
}
order.Print() // 状态: approved
// === 3. 尝试设置非法状态(演示校验)===
err = order.UpdateStatus("cancelled") // ❌ 非法状态
if err != nil {
fmt.Printf("❌ 更新失败: %v\n", err)
}
// === 4. JSON 序列化(用于 API 输出)===
data, err := json.Marshal(order)
if err != nil {
log.Fatal(err)
}
fmt.Printf("📤 JSON 输出: %s\n", data)
// 输出: {"id":"O1001","name":"iPhone 16","status":"approved"}
// === 5. JSON 反序列化(模拟 API 输入)===
jsonInput := `{"id":"O1002", "name":"AirPods", "status":"rejected"}`
var order2 Order
err = json.Unmarshal([]byte(jsonInput), &order2)
if err != nil {
log.Fatal(err)
}
order2.Print() // 状态: rejected
// === 6. 再次尝试反序列化非法状态 ===
invalidJSON := `{"id":"O1003", "name":"非法订单", "status":"cancelled"}`
var order3 Order
err = json.Unmarshal([]byte(invalidJSON), &order3)
if err != nil {
fmt.Printf("❌ 反序列化失败: %v\n", err)
} else {
fmt.Printf("⚠️ 警告:非法状态被接受: %s\n", order3.Status)
}
}
结果
text
📦 订单 ID: O1001, 名称: iPhone 16, 状态: pending
📦 订单 ID: O1001, 名称: iPhone 16, 状态: approved
❌ 更新失败: 无效的订单状态: cancelled
📤 JSON 输出: {"id":"O1001","name":"iPhone 16","status":"approved"}
📦 订单 ID: O1002, 名称: AirPods, 状态: rejected
❌ 反序列化失败: invalid status: cancelled
枚举
go
package main
import (
"fmt"
)
// 1. 定义枚举结构体
type OrderStatus struct {
Code int
Desc string
Color string
}
// 2. 私有构造函数(确保只能通过预定义方式创建)
func newStatus(code int, desc, color string) OrderStatus {
return OrderStatus{Code: code, Desc: desc, Color: color}
}
// 3. 定义枚举常量(全局变量)
var (
OrderPending = newStatus(100, "待处理", "yellow")
OrderApproved = newStatus(200, "已批准", "green")
OrderRejected = newStatus(400, "已拒绝", "red")
)
// 4. 所有枚举值列表(用于校验)
var AllOrderStatuses = []OrderStatus{
OrderPending,
OrderApproved,
OrderRejected,
}
// 5. 实现 String() 方法
func (s OrderStatus) String() string {
return s.Desc
}
// 6. 校验是否是合法枚举值
func (s OrderStatus) IsValid() bool {
for _, valid := range AllOrderStatuses {
if s == valid {
return true
}
}
return false
}
// 7. 根据 code 查找枚举项(可选)
func OrderStatusByCode(code int) (OrderStatus, bool) {
for _, s := range AllOrderStatuses {
if s.Code == code {
return s, true
}
}
return OrderStatus{}, false
}
func main() {
// 1. 使用预定义枚举
status := OrderApproved
fmt.Printf("状态: %s\n", status) // 输出: 状态: 已批准
fmt.Printf("代码: %d\n", status.Code) // 输出: 代码: 200
fmt.Printf("颜色: %s\n", status.Color) // 输出: 颜色: green
// 2. 校验
if status.IsValid() {
fmt.Println("✅ 合法状态")
}
// 3. 根据 code 查找
if s, ok := OrderStatusByCode(100); ok {
fmt.Printf("Code 100 对应: %s\n", s)
}
}
结果
text
状态: 已批准
代码: 200
颜色: green
✅ 合法状态
Code 100 对应: 待处理