One impediment is that Go cannot prevent the construction of invalid values, because every type has an implicit zero value:
type NonZeroInt struct {
v int
}
func (n NonZeroInt) Get() int {
return n.v
}
var n NonZeroInt // invalid!
You could of course validate on read:
func (n NonZeroInt) Get() (int, bool) {
if n.v == 0 {
return 0, false
}
return n.v
}
…but that's hardly good design.
You can improve on this marginally with an interface, because an interface's zero value is at least nil, which is, at least, explicit about whether there is a value or not. But it's not very elegant:
type NonZeroInt interface {
Get() int
}
type nonZeroInt struct {
v int
}
func (n nonZeroInt) Get() { return n.v }
func ToNonZeroInt(v int) (NonZeroInt, bool) {
if v == 0 {
return nil, false
}
return nonZeroInt{v}, true
}
The biggest problem with this approach is that it adds overhead. It can also force values to be heap-allocated, though I believe Go will still optimize single-word interface values to avoid this.
Note that since Go interfaces use structural typing, naming the method Get() can cause issues:
type AnyInt struct {
v int
}
func (n AnyInt) Get() int {
return n.v
}
Now AnyInt fulfills the NonZeroInt interface, which is of course not something we want. So for types like these, it's a good idea to name the method explicitly:
type NonZeroInt interface {
GetNonZero() int
}