I have a list of events (enum) which defines the particular event:
package events
const (
NEW_USER = "NEW_USER"
DIRECT_MESSAGE = "DIRECT_MESSAGE"
DISCONNECT = "DISCONNECT"
)
And there is a struct that will use this enum as one of its attribute
type ConnectionPayload struct {
EventName string `json:"eventName"`
EventPayload interface{} `json:"eventPayload"`
}
Is there a way I can use enum
as a type for EventName instead of string?
This is possible in typescript
not sure how to do it in golang.
I want the developers to forcefully use correct event name using the enum instead of making a mistake by using any random string for eventname.
CodePudding user response:
You can do it by generating code like the below.
type EventNames string
const (
NEW_USER EventNames = "NEW_USER"
DIRECT_MESSAGE EventNames = "DIRECT_MESSAGE"
DISCONNECT EventNames = "DISCONNECT"
)
then change your struct to this:
type ConnectionPayload struct {
EventName EventNames `json:"eventName"`
EventPayload interface{} `json:"eventPayload"`
}
CodePudding user response:
Try this:
package main
import (
"fmt"
"gopkg.in/go-playground/validator.v9"
)
type EventName string
const (
NEW_USER EventName = "NEW_USER"
DIRECT_MESSAGE EventName = "DIRECT_MESSAGE"
DISCONNECT EventName = "DISCONNECT"
)
type ConnectionPayload struct {
EventName EventName `json:"eventName" validate:"oneof=NEW_USER DIRECT_MESSAGE DISCONNECT"`
EventPayload interface{} `json:"eventPayload"`
}
func (s *ConnectionPayload) Validate() error {
validate := validator.New()
return validate.Struct(s)
}
func main() {
a := ConnectionPayload{
EventName: "NEW_USER",
}
b := ConnectionPayload{
EventName: "NEW_USERR",
}
err := a.Validate()
fmt.Println(a, err)
err = b.Validate()
fmt.Println(b, err)
}
CodePudding user response:
There is no enum type at the moment in go, and there currently isn't a direct way to enforce the same rules as what typescript does.
A common practice in go is to use the suggestion posted by @ttrasn :
define a custom type, and typed constants with your "enum" values :
type EventName string
const (
NEW_USER EventName = "NEW_USER"
DIRECT_MESSAGE EventName = "DIRECT_MESSAGE"
DISCONNECT EventName = "DISCONNECT"
)
This allows you to flag, in your go code, the places where you expect such a value :
// example function signature :
func OnEvent(e EventName, id int) error { ... }
// example struct :
type ConnectionPayload struct {
EventName EventName `json:"eventName"`
EventPayload interface{} `json:"eventPayload"`
}
and it will prevent assigning a plain string
to an EventName
var str string = "foo"
var ev EventName
ev = str // won't compile
OnEvent(str, 42) // won't compile
The known limitations are :
- in go, there is always a zero value :
var ev EventName // ev is ""
- string litterals are not the same as typed variables, and can be assigned :
var ev EventName = "SOMETHING_ELSE"
- casting is allowed :
var str string = "foo" var ev EventName = EventName(str)
- there is no check on unmarshalling :
jsn := []byte(`{"eventName":"SOMETHING_ELSE","eventPayload":"some message"}`) err := json.Unmarshal(jsn, &payload) // no error
https://go.dev/play/p/vMUTpvH8DBb
If you want some stricter checking, you would have to write a validator or a custom unmarshaler yourself.