Given this code:
type Philosopher int
const (
Epictetus Philosopher = iota
Seneca
)
func Quote(who Philosopher) string {
fmt.Println("t: ", reflect.TypeOf(who))
switch who {
case Epictetus:
return "First say to yourself what you would be;
and do what you have to do"
case Seneca:
return "If a man knows not to which port he sails,
No wind is favorable"
}
return "nothing"
}
Calling Quote(5)
will print Foo.Philosopher
as the type for 5.
Why didn't the type checker complain since that is what a type safe enums are supposed to do i.e. limit the scope of values ?
These are not enums as you think of them. Type Philosopher
is more or less an alias of an int. More or less, because it is a fundamentally distinct type, which can define its own methods.
The point of it is to provide semantic grouping of constants in a way that is clear to the programmer. Additionally, one gets the benefit of Go's type checker during compile time. But only to the degree that a value passed into a func(Philosopher)
can not be implicitly interpreted as such. Passing a literal 5
as the parameter works, because constants like that in Go are inherently untyped. This will not work;
n := 5
Quote(n) // Compile error -> int is not Philosopher
Reason being that n
is defined as int
. There exists no implicit conversion between type int
and Philosopher
. However, this will work:
n := 5
Quote(Philosopher(n))
Because the type cast is valid. Go does not care whether or not 5
is a valid and pre-defined Philosopher
constant.
Go doesn’t make any guarantees about valid values, except for those implied by int. The use of iota is just a convenience for defining a series of constants; it doesn’t say anything about valid values.
5 is a valid int, and therefore a valid Philosopher. You could also create const Plato = Philosopher(5).
Shorter answer should be like :
An untyped constant takes the type needed by its context.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With