This question already has an answer here:
What's a data structure that only allows one of a possible set of options?
I tried playing around with enum
s but they are not what I want.
package main
import "fmt"
type Event struct {
day_number Day
}
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
func main() {
var r Event
r.day_number = Monday
fmt.Println(r.day_number)
// Keep this from happening.
var impossible Event
impossible.day_number = 12
fmt.Println(impossible.day_number)
}
</div>
You could hide away the member field using a different package. This limits ways of creating the structure to functions from that package, and you can then control those functions to accept a limited set of inputs.
foo/foo.go
:
package foo
import "fmt"
type entity int
const (
one entity = iota + 1
two
)
type Foo struct {
e entity
}
func (f Foo) Get() int {
return int(f.e)
}
func NewFoo(i int) Foo {
switch i {
case 1:
return Foo{one}
case 2:
return Foo{two}
default:
panic(fmt.Errorf("%s", "foo"))
}
}
bar.go
:
package main
import "fmt"
import "./foo"
func main() {
f := foo.NewFoo(2)
fmt.Println(f.Get())
e := foo.Foo{3} // Error: implicit assignment of unexported field 'e' in foo.Foo literal
fmt.Println(e.Get())
d := foo.NewFoo(3) // panic: foo!
fmt.Println(d.Get())
}
You cannot create a Foo
struct outside of the foo
package, and the only function that creates Foo
structs in a foo
package accepts only a limited set of values.
I'm not sure this makes much sense since your day_number
field is already inaccessible outside your package.
Still, if this is really necessary, you'd set the private field via a method that validates the input such as the SetDay
method below:
func (d Day) String() string {
if v, ok := map[Day]string{
Monday: "Monday",
Tuesday: "Tuesday",
Wednesday: "Wednesday",
Thursday: "Thursday",
Friday: "Friday",
Saturday: "Saturday",
Sunday: "Sunday",
}[d]; ok {
return v
}
return "Bad day"
}
func (e *Event) SetDay(d Day) error {
if v := d.String(); v == "Bad day" {
return fmt.Errorf(v)
}
e.day_number = d
return nil
}