众所周知,go 没有联合类型,只能通过接口来模拟。
我尝试了两种方法来模拟联合,但结果远不如C。
package main
import (
"fmt"
"time"
)
type U interface {
i32() int32
i16() int16
}
type i32 int32
func (u i32) i32() int32 {
return int32(u)
}
func (u i32) i16() int16 {
return int16(u)
}
type i16 int16
func (u i16) i32() int32 {
return int32(u)
}
func (u i16) i16() int16 {
return int16(u)
}
func test() (total int64) {
type A struct {
t int32
u interface{}
}
a := [...]A{{1, int32(100)}, {2, int16(3)}}
for i := 0; i < 5000000000; i++ {
p := &a[i%2]
switch p.t {
case 1:
total += int64(p.u.(int32))
case 2:
total += int64(p.u.(int16))
}
}
return
}
func test2() (total int64) {
type A struct {
t int32
u U
}
a := [...]A{{1, i32(100)}, {2, i16(3)}}
for i := 0; i < 5000000000; i++ {
p := &a[i%2]
switch p.t {
case 1:
total += int64(p.u.i32())
case 2:
total += int64(p.u.i16())
}
}
return
}
type testfn func() int64
func run(f testfn) {
ts := time.Now()
total := f()
te := time.Now()
fmt.Println(total)
fmt.Println(te.Sub(ts))
}
func main() {
run(test)
run(test2)
}
结果:
257500000000
1m23.508223094s
257500000000
34.95081661s
method 方式更好,type-cast 方式消耗更多的 CPU 时间。
C版:
#include <stdio.h>
struct A {
int t;
union {
int i;
short v;
} u;
};
long test()
{
struct A a[2];
a[0].t = 1;
a[0].u.i = 100;
a[1].t = 2;
a[1].u.v = 3;
long total = 0;
long i;
for (i = 0; i < 5000000000; i++) {
struct A* p = &a[i % 2];
switch(p->t) {
case 1:
total += p->u.i;
break;
case 2:
total += p->u.v;
break;
}
}
return total;
}
int main()
{
long total = test();
printf("%ld\n", total);
}
结果:
257500000000
real 0m5.620s
user 0m5.620s
sys 0m0.000s
联合类型对许多应用程序很有用,例如网络协议可能包含变体具体类型。那么联合数据的访问可能会成为应用的瓶颈。
有人可以帮忙吗?谢谢。
原文由 kingluo 发布,翻译遵循 CC BY-SA 4.0 许可协议
您可以使用数组将单个
int32
表示为两个int16
s,然后 按照 Rob Pike 的建议 将它们组合起来:使用原始的 Go 编译器,它的运行速度比 C 版本慢 2 倍左右,而使用 gccgo (-O3),它的运行速度与 C 版本差不多。
请注意,此方法采用小字节序整数。您需要切换大端架构的轮班顺序。
此外,如果您需要从字节切片中解码结构,您实际上应该使用
encoding/binary
。创建此库是为了在字节序列和其他类型之间进行转换。