Idea from following video.
列挙型の作り方を再考する - Go Conference 2023 Online
This package provides support for defining Visitor
and implementing Accept()
methods.
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 inFruits
type.
type (
// enum interface
Fruits interface{
FruitsEnum
}
...
- Implement your visitor type!
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-impl |
generate Visitor implementation and its factory |
The value of --visitor
option consists of three parts with the delimiter ":".
- The target type name(enum identifier 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.
The value of --accept
option consists of two parts with the delimiter ":".
- The target type name(enum identifier 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.
The value of --visitor-impl
option consists of one part or two parts with the delimiter ":".
- The target type name(enum identifier interface) to implement.
Pattern match using*
is allowed. - The factory function name pattern(if omitted, use
"New*"
).
If the pattern contains*
, it will replaced with the target type name.
If you need return type T of visitor (and accept) methods, embed enum.VisitorReturns[T]
to enum identifier interface.
type Fruits interface {
enum.VisitorReturns[error]
}
Preceding enum identifier derives following code.
type (
FruitsVisitor interface {
VisitApple(e Apple) error
VisitOrange(e Orange) error
VisitGrape(e Grape) error
}
FruitsEnum interface {
Accept(v FruitsVisitor) error
}
)
func (e Apple) Accept(v FruitsVisitor) error {
return v.VisitApple(e)
}
func (e Orange) Accept(v FruitsVisitor) error {
return v.VisitOrange(e)
}
func (e Grape) Accept(v FruitsVisitor) error {
return v.VisitGrape(e)
}
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" --visitor-impl="*"
type (
Event interface {
ID() string
enum.VisitorReturns[error]
}
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{}}
type __EventHandler struct {
__OnOrderPlaced func(OrderPlaced) error
__OnPaymentReceived func(PaymentReceived) error
__OnItemShipped func(ItemShipped) error
}
func NewEventHandler(__OnOrderPlaced func(e OrderPlaced) error, __OnPaymentReceived func(e PaymentReceived) error, __OnItemShipped func(e ItemShipped) error) EventHandler {
return &__EventHandler{__OnOrderPlaced: __OnOrderPlaced, __OnPaymentReceived: __OnPaymentReceived, __OnItemShipped: __OnItemShipped}
}
func (v __EventHandler) OnOrderPlaced(e OrderPlaced) error {
return v.__OnOrderPlaced(e)
}
func (v __EventHandler) OnPaymentReceived(e PaymentReceived) error {
return v.__OnPaymentReceived(e)
}
func (v __EventHandler) OnItemShipped(e ItemShipped) error {
return v.__OnItemShipped(e)
}