I found this trick recently to replicate a C union in Go with
unsafe.Sizeof, arrays, and some constant arithmetic. This lets you
stack-allocate data that needs to be the max size of multiple other data
types. So given a type A and B that you want to union, you can say
const ASize = int64(unsafe.Sizeof(*new(A)))
const BSize = int64(unsafe.Sizeof(*new(B)))
const diff = ASize - BSize
const max = ASize - ((diff>>(bits.UintSize-1))&1)*diff
var storage [max]byte
*(*A)(unsafe.Pointer(&storage))
*(*B)(unsafe.Pointer(&storage))
This process can be repeated for any number of types. For example, if you
wanted to represent a tagged union defined like
type A =
| B
| C int
| D (a: int, b: int)
you could lower it to something like
const size = int64(unsafe.Sizeof(*new(B)))
const size0 = int64(unsafe.Sizeof(*new(C)))
const diff = size - size0
const max = size - diff*((diff>>(bits.UintSize-1))&1)
const size1 = int64(unsafe.Sizeof(*new(D)))
const diff0 = size1 - max
const max0 = size1 - diff0*((diff0>>(bits.UintSize-1))&1)
type A struct {
tag uint8
storage [max0]byte
}
type B struct{}
type C int
type D struct {
a int
b int
}
Unfortunately, the resulting code is pretty inefficient compared to
interfaces or struct embedding. It might be that the use of unsafe is
hindering compiler optimizations, or maybe it's an alignment issue.
--
You received this message because you are subscribed to the Google Groups
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/golang-nuts/5d150c6a-3ecb-4cb8-91b3-c048940294aen%40googlegroups.com.