A Go linter checks that untyped constant expressions are used as values of defined type (a.k.a. named type).
go install github.com/jiftechnify/untypedconst/cmd/untypedconst@latest
untypedconst ./...
When you want to define enums in Go, you should go through following steps:
- Define an "defined type" for the enum.
- Define enum variants as values of the type you defined in 1.
Or, you should write a code like this:
type TrafficLight int
const (
None TrafficLight = iota // 0
Green // 1
Yellow // 2
Red // 3
)
Then you use it like:
func next(tl TrafficLight) TrafficLight {
switch tl {
case Green:
return Yellow
case Yellow:
return Red
case Red:
return Green
case None:
return None
default:
panic("boom!")
}
}
func good() {
tl := next(Green) // tl == Yellow
}
So far so good, until you write a code like this by accident:
func bad() {
tl := next(4) // it compiles, unfortunately
// => boom!
}
In the code above, 4
is an "untyped constant", and when you "use" it (assign it to a variable, pass it to a function, etc.), it is assigned the most suited type from the context, i.e. TrafficLight
. So types match and it compiles despite the actual value is out of the range of TrafficLight
! It's a pity that Go compiler doesn't come with a feature that prevents us from breaking codes in such a way.
untypedconst (indirectly) detects such a mistake by checking whether you don't use untyped constants in places that require values of some defined type:
func bad() {
tl := next(4)
// => passing untyped constant to parameter of defined type "TrafficLight"
}
MIT