Home > Backend Development > Golang > Go Enum's problems and solutions with xybor-x/enum

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

DDD
Release: 2024-12-19 18:44:11
Original
843 people have browsed it

What is enum?

An enum, short for enumeration, is a special data type that represents a set of named values. It is used to define a collection of constant values that are conceptually related, improving code readability and reducing errors caused by the use of arbitrary literal values.

// Enum in Java
enum TrafficLight {
    RED, YELLOW, GREEN
}
Copy after login
Copy after login
# Enum in Python
from enum import Enum

class TrafficLight(Enum):
    RED = 1
    GREEN = 2
    BLUE = 3
Copy after login

Enum in Go

Go doesn’t support enum natively. However, there is a popular way to define an enum in Go is using iota approach.

package main

type TrafficLight int

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

func main() {
    fmt.Println(RED) // Output: 0
}
Copy after login

However, there are some problems when dealing with enum in this way:

  • Lack of Built-in Methods: No direct support for features like listing all enum values or converting between strings and enums.
  • Limited Type Safety: Enums are typically represented using basic types (e.g., int or string), which increases the risk of unintended assignments.
  • Serialization and Deserialization Complexity: Mapping enums to and from formats like JSON requires additional handling.

The xybor-x/enum library

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

The xybor-x/enum libray provides elegant, easy-to-use, and powerful solutions for Go enum with no code generation.

There are some types of enum which you can work with xybor-x/enum, please choose the most suitable one.

Basic enum

Pros ?

  • Simple.
  • Supports constant values.

Cons ?

  • No built-in methods.
  • No type safety.
  • Lacks serialization and deserialization support. Like the traditional enum, the basic enum has no built-in methods. But you can use utility functions of xybor-x/enum to handle this type of 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"
}
Copy after login

WrapEnum

Pros ?

  • Supports constant values.
  • Provides many useful built-in methods.
  • Full serialization and deserialization support out of the box.

Cons ?

  • Provides only basic type safety.
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"
}
Copy after login

WrapEnum is the most suitable enum for general cases. However, it only provides basic type safety. If you want a stricter one, consider using SafeEnum.

// WrapEnum cannot prevent this type of invalid declaration.
// Consider using SafeEnum.
r := Role(42)
Copy after login

SafeEnum

SafeEnum defines a strong type-safe enum. Like WrapEnum, it provides a set of built-in methods to simplify working with enums.

The SafeEnum enforces strict type safety, ensuring that only predefined enum values are allowed. It prevents the accidental creation of new enum types, providing a guaranteed set of valid values.

Pros ?

  • Provides strong type safety.
  • Provides many useful built-in methods.
  • Full serialization and deserialization support out of the box.

Cons ?

  • Does not support constant values.

Why is constant-support important?

Some static analysis tools (such as nogo for bazel, golangci-lint with exhaustive extension) support checking for exhaustive switch statements in constant enums. By choosing an enum with constant support, you can enable this functionality in these tools.

// Enum in Java
enum TrafficLight {
    RED, YELLOW, GREEN
}
Copy after login
Copy after login

References

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

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

The above is the detailed content of Go Enum's problems and solutions with xybor-x/enum. For more information, please follow other related articles on the PHP Chinese website!

source:dev.to
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template