首页 > 后端开发 > Golang > Go Enum 与 xybor-x/enum 的问题及解决方案

Go Enum 与 xybor-x/enum 的问题及解决方案

DDD
发布: 2024-12-19 18:44:11
原创
843 人浏览过

什么是枚举?

枚举(enumeration)的缩写,是一种特殊的数据类型,表示一组命名值。它用于定义概念上相关的常量值的集合,提高代码可读性并减少由于使用任意文字值而导致的错误。

// Enum in Java
enum TrafficLight {
    RED, YELLOW, GREEN
}
登录后复制
登录后复制
# Enum in Python
from enum import Enum

class TrafficLight(Enum):
    RED = 1
    GREEN = 2
    BLUE = 3
登录后复制

Go 中的枚举

Go 本身不支持枚举。然而,在 Go 中定义枚举的流行方法是使用 iota 方法。

package main

type TrafficLight int

const (
    RED TrafficLight = iota // 0
    GREEN                   // 1
    BLUE                    // 2
)

func main() {
    fmt.Println(RED) // Output: 0
}
登录后复制

但是,以这种方式处理枚举时存在一些问题:

  • 缺乏内置方法:不直接支持列出所有枚举值或在字符串和枚举之间转换等功能。
  • 有限类型安全:枚举通常使用基本类型(例如 int 或 string)表示,这会增加意外分配的风险。
  • 序列化和反序列化复杂性:将枚举映射到 JSON 等格式或从 JSON 等格式映射需要额外的处理。

xybor-x/enum 库

Go Enum’s problems and solutions with xybor-x/enum

xybor-x/enum 库为 Go 枚举提供了优雅、易于使用且功能强大的解决方案,无需生成代码。

有一些类型的枚举可以与 xybor-x/enum 一起使用,请选择最合适的一种。

基本枚举

优点?

  • 简单。
  • 支持常量值。

缺点?

  • 没有内置方法。
  • 没有类型安全。
  • 缺乏序列化和反序列化支持。 与传统枚举一样,基本枚举没有内置方法。但是您可以使用 xybor-x/enum 的实用函数来处理这种类型的枚举。
package main

type Role int

const (
    RoleUser Role = iota
    RoleAdmin
)

func init() {
    enum.Map(RoleUser, "user")
    enum.Map(RoleAdmin, "admin")

    // Optional: ensure no new enum values can be added to Role.
    enum.Finalize[Role]()
}

func main() {
    // Print the corresponding string.
    fmt.Println(enum.ToString(RoleUser)) // Output: user

    // Print out all valid enums.
    fmt.Println(enum.All[Role]())       // Output: [0 1]

    // Parse an enum from int.
    r1, ok := enum.FromInt[Role](1)
    fmt.Println(ok)                // Output: true
    fmt.Println(enum.ToString(r1)) // Output: admin

    // Parse an enum from string.
    r2, ok := enum.FromString[Role]("admin")
    fmt.Println(ok) // Output: true
    fmt.Println(r2) // Output: 1

    // Serialize json.
    data, err := enum.MarshalJSON(RoleUser)
    fmt.Println(err)          // Output: nil
    fmt.Println(string(data)) // Output: "user"
}
登录后复制

包裹枚举

优点?

  • 支持常量值。
  • 提供了许多有用的内置方法。
  • 开箱即用的完整序列化和反序列化支持。

缺点?

  • 仅提供基本类型安全。
package main

// Only need to change the two following lines fromthe Basic enum.
type role any
type Role = enum.WrapEnum[role]

const (
    RoleUser Role = iota
    RoleAdmin
)

func init() {
    enum.Map(RoleUser, "user")
    enum.Map(RoleAdmin, "admin")

    // Optional: ensure no new enum values can be added to Role.
    enum.Finalize[Role]()
}

func main() {
    // Print the corresponding string. No need to use enum.ToString.
    fmt.Println(RoleUser) // Output: user

    // Print out all valid enums.
    fmt.Println(enum.All[Role]())       // Output: [user admin]

    // Parse an enum from int.
    r1, ok := enum.FromInt[Role](1)
    fmt.Println(ok) // Output: true
    fmt.Println(r1) // Output: admin

    // Parse an enum from string.
    r2, ok := enum.FromString[Role]("admin")
    fmt.Println(ok) // Output: true
    fmt.Println(r2) // Output: admin

    // Now you can use json.Marshal instead of enum.MarshalJSON.
    data, err := json.Marshal(RoleUser)
    fmt.Println(err)          // Output: nil
    fmt.Println(string(data)) // Output: "user"
}
登录后复制

WrapEnum 是最适合一般情况的枚举。然而,它只提供基本的类型安全。如果您想要更严格的,请考虑使用 SafeEnum。

// WrapEnum cannot prevent this type of invalid declaration.
// Consider using SafeEnum.
r := Role(42)
登录后复制

安全枚举

SafeEnum 定义了一个强类型安全枚举。与 WrapEnum 一样,它提供了一组内置方法来简化枚举的使用。

SafeEnum 强制执行严格的类型安全,确保只允许预定义的枚举值。它可以防止意外创建新的枚举类型,从而提供一组有保证的有效值。

优点?

  • 提供强大的类型安全性。
  • 提供了许多有用的内置方法。
  • 开箱即用的完整序列化和反序列化支持。

缺点?

  • 不支持常量值。

为什么持续支持很重要?

一些静态分析工具(例如 bazel 的 nogo、具有详尽扩展的 golangci-lint)支持检查常量枚举中的详尽 switch 语句。通过选择具有持续支持的枚举,您可以在这些工具中启用此功能。

// Enum in Java
enum TrafficLight {
    RED, YELLOW, GREEN
}
登录后复制
登录后复制

参考

xybor-x/enum:https://github.com/xybor-x/enum

中:https://medium.com/@huykingsofm/enum-handling-in-go-a2727154435e
越南语 viblo:https://viblo.asia/p/cac-van-de-cua-go-enum-va-cach-giai-quyet-voi-xybor-xenum-Yym401A9J91

以上是Go Enum 与 xybor-x/enum 的问题及解决方案的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板