Skip to content

Instantly share code, notes, and snippets.

@jordanorelli
Created November 29, 2021 04:39
Show Gist options
  • Save jordanorelli/e8cea239de173001aead852ac95a4c45 to your computer and use it in GitHub Desktop.
Save jordanorelli/e8cea239de173001aead852ac95a4c45 to your computer and use it in GitHub Desktop.
boxing a value into a union constraint
package main
import (
"fmt"
)
// Allowed is a constraint that matches specific types
type Allowed interface {
int | float64 | bool
}
// Boxed is a value that erases the type it contains
type Boxed struct {
val interface{}
}
func (b Boxed) Value() interface{} { return b.val }
// Box boxes an allowed value, but it's a compile-time error
// to try to box a type that's not allowed
func Box[T Allowed](v T) Boxed {
return Boxed{val: v}
}
// Unbox removes an allowed value from a box
func Unbox[T Allowed](b Boxed) (T, bool) {
v, ok := b.val.(T)
return v, ok
}
func Append[T Allowed](vals []Boxed, v T) []Boxed {
return append(vals, Box(v))
}
func main() {
var vals []Boxed
vals = Append(vals, 3)
vals = Append(vals, 10.2)
vals = Append(vals, true)
fmt.Println(vals)
// This is a compile-time error:
// vals = Append(vals, "nope")
// This may fail at run time. It will never fail at compile time.
v1, ok := vals[1].Value().(float64)
fmt.Println(v1, ok)
// This may fail at run time as well. It looks like it's the same
// thing, but it's not
v2, ok := Unbox[bool](vals[2])
fmt.Println(v2, ok)
// This fails at compile time because string is not in Allowed
// v0, ok := Unbox[string](vals[0])
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment