go-enum
Idea from following video.
列挙型の作り方を再考する - Go Conference 2023 Online
This package provides support for defining Visitor
and implementing Accept()
methods.
Usage
Examples here.
- Prepare enum interface and member types.
package fruits
import "github.com/daichitakahashi/go-enum"
type (
// enum interface
Fruits interface{}
// member types
Apple enum.MemberOf[Fruits]
Orange enum.MemberOf[Fruits]
Grape enum.MemberOf[Fruits]
)
- Run following command.
$ go run github.com/daichitakahashi/go-enum/cmd/enumgen
- Following code is generated with the file name
enum.gen.go
(file name is configurable).
// Code generated by enumgen. DO NOT EDIT.
package fruits
type (
FruitsVisitor interface {
VisitApple(e Apple)
VisitOrange(e Orange)
VisitGrape(e Grape)
}
FruitsEnum interface {
Accept(v FruitsVisitor)
}
)
func (e Apple) Accept(v FruitsVisitor) {
v.VisitApple(e)
}
func (e Orange) Accept(v FruitsVisitor) {
v.VisitOrange(e)
}
func (e Grape) Accept(v FruitsVisitor) {
v.VisitGrape(e)
}
var _ = []FruitsEnum{Apple{}, Orange{}, Grape{}}
- Optional: Embed generated
FruitsEnum
type in Fruits
type.
type (
// enum interface
Fruits interface{
FruitsEnum
}
...
- Implement your visitor type!
Options for enumgen
option |
description |
default value |
--wd |
working directory |
. |
--out |
output file name |
enum.gen.go |
--visitor |
customize Visitor type & method names |
*:*Visitor:Visit* |
--accept |
customize Accept method name |
*:Accept |
--visitor
option
The value of --visitor
option consists of three parts with the delimiter ":".
- The target type name(enum interface) of customization.
Pattern match using *
is allowed.
- The visitor type name pattern.
If the pattern contains *
, it will replaced with the target type name.
- The visit method name pattern.
If the pattern contains *
, it will replaced with the member type name.
--accept
option
The value of --accept
option consists of two parts with the delimiter ":"
- The target type name(enum interface) of customization.
Pattern match using *
is allowed.
- The accept method name pattern.
If the pattern contains *
, it will replaced with the target type name.
--visitor
and --accept
options can be used multiple times.
Example: use enumgen for domain events.
package event
import (
"time"
"github.com/daichitakahashi/go-enum"
)
//go:generate go run github.com/daichitakahashi/go-enum/cmd/enumgen@latest --visitor="Event:EventHandler:On*" --accept="Event:Emit"
type (
Event interface {
ID() string
}
OrderPlaced struct {
enum.MemberOf[Event]
Items []string
}
PaymentReceived struct {
enum.MemberOf[Event]
Amount int
}
ItemShipped struct {
enum.MemberOf[Event]
ShippedAt time.Time
}
)
// ID implements Event.
func (OrderPlaced) ID() string {
return "orderPlaced"
}
// ID implements Event.
func (PaymentReceived) ID() string {
return "paymentReceived"
}
// ID implements Event.
func (ItemShipped) ID() string {
return "itemShipped"
}
var (
_ Event = OrderPlaced{}
_ Event = PaymentReceived{}
_ Event = ItemShipped{}
)
go generated:
// Code generated by enumgen. DO NOT EDIT.
package event
type (
EventHandler interface {
OnOrderPlaced(e OrderPlaced)
OnPaymentReceived(e PaymentReceived)
OnItemShipped(e ItemShipped)
}
EventEnum interface {
Emit(v EventHandler)
}
)
func (e OrderPlaced) Emit(v EventHandler) {
v.OnOrderPlaced(e)
}
func (e PaymentReceived) Emit(v EventHandler) {
v.OnPaymentReceived(e)
}
func (e ItemShipped) Emit(v EventHandler) {
v.OnItemShipped(e)
}
var _ = []EventEnum{OrderPlaced{}, PaymentReceived{}, ItemShipped{}}