goenum

package module
v1.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 21, 2024 License: Apache-2.0 Imports: 5 Imported by: 1

README

Go 通用枚举实现

License Go Report Card codecov

怎么定义和使用枚举?

只需往枚举struct内嵌goenum.Enum, 即可定义一个枚举类型,并获得开箱即用的一组方法。

go get github.com/lvyahui8/goenum
import "github.com/lvyahui8/goenum"

// 声明枚举类型
type State struct {
    goenum.Enum
}

// 定义枚举
var (
    Created = goenum.NewEnum[State]("Created")
    Running = goenum.NewEnum[State]("Running")
    Success = goenum.NewEnum[State]("Success")
)

// Usage
Created.Name() // string "Created"
Created.Ordinal() // int 0
goenum.ValueOf[State]("Created") // struct instance: Created
Created.Equals(*goenum.ValueOf[State]("Created")) // true
goenum.Values[State]() // equals []State{Created,Running,Success}

实例方法

type EnumDefinition interface {
    // Stringer 支持打印输出
    fmt.Stringer
    // Marshaler 支持枚举序列化
    json.Marshaler
    // Init 枚举初始化。使用方不应该直接调用这个方法。
    Init(args ...any) any
    // Name 枚举名称,同一类型枚举应该唯一
    Name() string
    // Equals 枚举对比
    Equals(other EnumDefinition) bool
    // Type 实际的枚举类型
    Type() string
    // Ordinal 获取枚举序数
    Ordinal() int
    // Compare 枚举比较方法
    Compare(other EnumDefinition) int
}

工具方法

  • ValueOf 根据字符串获取枚举,如果找不到,则返回nil

  • ValueOfIgnoreCase 忽略大小写获取枚举, 涉及到一次反射调用,性能比ValueOf略差

  • Values 返回所有枚举

  • GetEnumMap 获取所有枚举,以name->enum map的形式返回

  • EnumNames 获取一批枚举的名称

  • GetEnums 根据枚举名字列表获得一批枚举

  • IsValidEnum 判断是否是合法的枚举

func TestHelpers(t *testing.T) {
    t.Run("ValueOf", func(t *testing.T) {
        require.True(t, Owner.Equals(*goenum.ValueOf[Role]("Owner")))
        require.False(t, Developer.Equals(*goenum.ValueOf[Role]("Owner")))
    })
    t.Run("ValueOfIgnoreCase", func(t *testing.T) {
        require.True(t, Owner.Equals(*goenum.ValueOfIgnoreCase[Role]("oWnEr")))
        require.False(t, Reporter.Equals(*goenum.ValueOfIgnoreCase[Role]("oWnEr")))
    })
    t.Run("Values", func(t *testing.T) {
        require.True(t, reflect.DeepEqual([]Role{Reporter, Developer, Owner}, goenum.Values[Role]()))
    })
    t.Run("GetEnumMap", func(t *testing.T) {
        enumMap := goenum.GetEnumMap[Role]()
        require.True(t, len(enumMap) == 3)
        role, exist := enumMap["Owner"]
        require.True(t, exist)
        require.True(t, role.Equals(Owner))
    })
    t.Run("EnumNames", func(t *testing.T) {
        require.True(t, reflect.DeepEqual([]string{"Owner", "Developer"}, goenum.EnumNames(Owner, Developer)))
    })
    t.Run("IsValidEnum", func(t *testing.T) {
        require.True(t, goenum.IsValidEnum[Role]("Owner"))
        require.False(t, goenum.IsValidEnum[Role]("Test"))
    })
}

更多特性支持

复杂枚举初始化

枚举struct 实现Init方法即可,NewEnum方法中的args参数,会完整透传给Init方法,注意,Init方法需要将receiver返回以确保初始化生效

完整例子请看 gitlab_role_perms

type Module struct {
    goenum.Enum
    perms    []Permission
    basePath string
}

func (m Module) Init(args ...any) any {
    m.perms = args[0].([]Permission)
    m.basePath = args[1].(string)
    return m
}

func (m Module) GetPerms() []Permission {
    return m.perms
}

func (m Module) BasePath() string {
    return m.basePath
}


// 定义模块
var (
    Issues        = goenum.NewEnum[Module]("Issues", []Permission{AddLabels, AddTopic}, "/issues/")
    MergeRequests = goenum.NewEnum[Module]("MergeRequests", []Permission{ViewMergeRequest, ApproveMergeRequest, DeleteMergeRequest}, "/merge/")
)
EnumSet

api声明

// EnumSet 枚举set,一般在枚举非常多时使用
type EnumSet[E EnumDefinition] interface {
	// Stringer 支持标准输出及格式化
	fmt.Stringer
	// Marshaler 支持json序列化
	json.Marshaler
	// Add 往set添加元素,添加成功则返回true,如果已经存在则返回false
	Add(e E) bool
	// AddRange 按照枚举的序数,连续添加一段枚举,返回实际添加的数量(排除已经存在的)
	AddRange(begin, end E) int
	// Remove 删除元素,删除成功则返回true,如果元素原本不存在则返回false
	Remove(e E) bool
	// RemoveRange  按照枚举的序数,连续删除一段枚举,返回实际删除的数量(排除原本不存在的)
	RemoveRange(begin, end E) int
	// IsEmpty set是否为空
	IsEmpty() bool
	// Clear 清理set
	Clear()
	// Len set内当前的枚举数量
	Len() int
	// Contains 是否包含指定的枚举,只要有1个不存在则返回false
	Contains(enums ...E) bool
	// ContainsAll  判断是否包含另外一个enumSet(子集关系)
	ContainsAll(set EnumSet[E]) bool
	// Equals 判断两个EnumSet是否相同
	Equals(set EnumSet[E]) bool
	// Each set迭代方法, f方法如果返回false,则中止迭代
	Each(f func(e E) bool)
	// Names 返回set中已有枚举的Name表示
	Names() []string
	// Clone 深拷贝一份set
	Clone() EnumSet[E]
}

EnumSet usage

stmtSet := NewUnsafeEnumSet[Statement]()

stmtSet.Add(Decl)
stmtSet.IsEmpty()
stmtSet.Contains(Decl)
stmtSet.Len() == 1
stmtSet.AddRange(Comm, Range)
stmtSet.Remove(Decl)

完整例子请看 enum_set_test

ValueOf性能测试

不用担心任何性能问题,反射调用基本集中在NewEnum方法中,其他方法尽量避免反射调用。

goos: linux
goarch: arm64
pkg: github.com/lvyahui8/goenum/internal
BenchmarkValueOf/ValueOf-4             1000000000             0.0002492 ns/op           0 B/op           0 allocs/op
BenchmarkValueOf/ValueOf-4             1000000000             0.0002966 ns/op           0 B/op           0 allocs/op
BenchmarkValueOf/ValueOf-4             1000000000             0.0002713 ns/op           0 B/op           0 allocs/op
BenchmarkValueOf/ValueOfIgnoreCase-4             1000000000             0.002228 ns/op           0 B/op           0 allocs/op
BenchmarkValueOf/ValueOfIgnoreCase-4             1000000000             0.002611 ns/op           0 B/op           0 allocs/op
BenchmarkValueOf/ValueOfIgnoreCase-4             1000000000             0.002606 ns/op           0 B/op           0 allocs/op
PASS
ok      github.com/lvyahui8/goenum/internal    0.097s

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func EnumNames

func EnumNames[T EnumDefinition](enums ...T) (names []string)

EnumNames 获取一批枚举的名称

func GetEnumMap

func GetEnumMap[T EnumDefinition]() map[string]T

GetEnumMap 获取所有枚举,以name->enum map的形式返回

func GetEnums added in v1.2.0

func GetEnums[T EnumDefinition](names ...string) (res []T)

GetEnums 根据枚举名字列表获得一批枚举

func IsValidEnum

func IsValidEnum[T EnumDefinition](name string) bool

IsValidEnum 判断是否是合法的枚举

func NewEnum

func NewEnum[T EnumDefinition](name string, args ...any) T

NewEnum 新建枚举, 如果枚举(同类型)已经存在,则会抛出panic,禁止重复创建枚举

func Size added in v1.1.0

func Size[T EnumDefinition]() int

func ValueOf

func ValueOf[T EnumDefinition](name string) *T

ValueOf 根据字符串获取枚举,如果找不到,则返回nil

func ValueOfIgnoreCase

func ValueOfIgnoreCase[T EnumDefinition](name string) *T

ValueOfIgnoreCase 忽略大小写获取枚举, 涉及到一次反射调用,性能比ValueOf略差

func Values

func Values[T EnumDefinition]() []T

Values 返回所有可用枚举,返回slice是有序的,按照ordinal排序

Types

type Enum

type Enum struct {
	// contains filtered or unexported fields
}

func (Enum) Compare

func (e Enum) Compare(other EnumDefinition) int

func (Enum) Equals

func (e Enum) Equals(other EnumDefinition) bool

func (Enum) Init

func (e Enum) Init(args ...any) any

func (Enum) MarshalJSON

func (e Enum) MarshalJSON() ([]byte, error)

func (Enum) MarshalText added in v1.2.0

func (e Enum) MarshalText() (text []byte, err error)

func (Enum) Name

func (e Enum) Name() string

func (Enum) Ordinal

func (e Enum) Ordinal() int

func (Enum) String

func (e Enum) String() string

func (Enum) Type

func (e Enum) Type() string

type EnumDefinition

type EnumDefinition interface {
	// Stringer 支持打印输出
	fmt.Stringer
	// Marshaler 支持枚举序列化
	json.Marshaler
	// TextMarshaler 支持枚举序列化
	encoding.TextMarshaler
	// Init 枚举初始化。使用方不应该直接调用这个方法。(即使调用也没有意义,这限定为一个值方法)
	Init(args ...any) any
	// Name 枚举名称,同一类型枚举应该唯一
	Name() string
	// Equals 枚举对比
	Equals(other EnumDefinition) bool
	// Type 实际的枚举类型
	Type() string
	// Ordinal 获取枚举序数
	Ordinal() int
	// Compare 枚举比较方法
	Compare(other EnumDefinition) int
}

type EnumSet added in v1.1.0

type EnumSet[E EnumDefinition] interface {
	// Stringer 支持标准输出及格式化
	fmt.Stringer
	// Marshaler 支持json序列化
	json.Marshaler
	// Add 往set添加元素,添加成功则返回true,如果已经存在则返回false
	Add(e E) bool
	// AddRange 按照枚举的序数,连续添加一段枚举,返回实际添加的数量(排除已经存在的)
	AddRange(begin, end E) int
	// Remove 删除元素,删除成功则返回true,如果元素原本不存在则返回false
	Remove(e E) bool
	// RemoveRange  按照枚举的序数,连续删除一段枚举,返回实际删除的数量(排除原本不存在的)
	RemoveRange(begin, end E) int
	// IsEmpty set是否为空
	IsEmpty() bool
	// Clear 清理set
	Clear()
	// Len set内当前的枚举数量
	Len() int
	// Contains 是否包含指定的枚举,只要有1个不存在则返回false
	Contains(enums ...E) bool
	// ContainsAll  判断是否包含另外一个enumSet(子集关系)
	ContainsAll(set EnumSet[E]) bool
	// Equals 判断两个EnumSet是否相同
	Equals(set EnumSet[E]) bool
	// Each set迭代方法, f方法如果返回false,则中止迭代
	Each(f func(e E) bool)
	// Names 返回set中已有枚举的Name表示
	Names() []string
	// Clone 深拷贝一份set
	Clone() EnumSet[E]
}

EnumSet 枚举set,一般在枚举非常多时使用

type UnsafeEnumSet added in v1.1.0

type UnsafeEnumSet[E EnumDefinition] struct {
	// contains filtered or unexported fields
}

func NewUnsafeEnumSet added in v1.1.0

func NewUnsafeEnumSet[E EnumDefinition]() *UnsafeEnumSet[E]

func (*UnsafeEnumSet[E]) Add added in v1.1.0

func (set *UnsafeEnumSet[E]) Add(e E) bool

func (*UnsafeEnumSet[E]) AddRange added in v1.1.0

func (set *UnsafeEnumSet[E]) AddRange(begin, end E) int

func (*UnsafeEnumSet[E]) Clear added in v1.1.0

func (set *UnsafeEnumSet[E]) Clear()

func (*UnsafeEnumSet[E]) Clone added in v1.1.0

func (set *UnsafeEnumSet[E]) Clone() EnumSet[E]

func (*UnsafeEnumSet[E]) Contains added in v1.1.0

func (set *UnsafeEnumSet[E]) Contains(enums ...E) bool

func (*UnsafeEnumSet[E]) ContainsAll added in v1.1.0

func (set *UnsafeEnumSet[E]) ContainsAll(enumSet EnumSet[E]) bool

func (*UnsafeEnumSet[E]) Each added in v1.1.0

func (set *UnsafeEnumSet[E]) Each(f func(e E) bool)

func (*UnsafeEnumSet[E]) Equals added in v1.1.0

func (set *UnsafeEnumSet[E]) Equals(enumSet EnumSet[E]) bool

func (*UnsafeEnumSet[E]) IsEmpty added in v1.1.0

func (set *UnsafeEnumSet[E]) IsEmpty() bool

func (*UnsafeEnumSet[E]) Len added in v1.1.0

func (set *UnsafeEnumSet[E]) Len() int

func (*UnsafeEnumSet[E]) MarshalJSON added in v1.1.0

func (set *UnsafeEnumSet[E]) MarshalJSON() ([]byte, error)

func (*UnsafeEnumSet[E]) Names added in v1.1.0

func (set *UnsafeEnumSet[E]) Names() []string

func (*UnsafeEnumSet[E]) Remove added in v1.1.0

func (set *UnsafeEnumSet[E]) Remove(e E) bool

func (*UnsafeEnumSet[E]) RemoveRange added in v1.1.0

func (set *UnsafeEnumSet[E]) RemoveRange(begin, end E) int

func (*UnsafeEnumSet[E]) String added in v1.1.0

func (set *UnsafeEnumSet[E]) String() string

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL