golang:如何有效地模拟联合类型

众所周知,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

方法方式更好,类型转换方式花费更多的CPU时间。


温温酱
浏览 388回答 3
3回答

慕妹3146593

您可以使用数组将单个表示int32为两个int16s,然后按照 Rob Pike 的建议将它们组合起来:func test3() (total int64) {&nbsp; &nbsp; type A struct {&nbsp; &nbsp; &nbsp; &nbsp; t int32&nbsp; &nbsp; &nbsp; &nbsp; u [2]int16&nbsp; &nbsp; }&nbsp; &nbsp; a := [...]A{&nbsp; &nbsp; &nbsp; &nbsp; {1, [2]int16{100, 0}},&nbsp; &nbsp; &nbsp; &nbsp; {2, [2]int16{3, 0}},&nbsp; &nbsp; }&nbsp; &nbsp; for i := 0; i < N; i++ {&nbsp; &nbsp; &nbsp; &nbsp; p := &a[i%2]&nbsp; &nbsp; &nbsp; &nbsp; switch p.t {&nbsp; &nbsp; &nbsp; &nbsp; case 1:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; total += int64(p.u[0]<<0 | p.u[1]<<8)&nbsp; &nbsp; &nbsp; &nbsp; case 2:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; total += int64(p.u[0])&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return}使用原始的 Go 编译器,它的运行速度比 C 版本慢约 2 倍,而使用 gccgo (-O3) 时,它的运行速度与 C 一样快。但请注意,这种方法假定小端整数。您需要切换大端架构的转换顺序。此外,如果您需要从字节切片解码结构,您应该真正使用encoding/binary. 创建这个库是为了在字节序列和其他类型之间进行转换。

慕田峪4524236

联合可能包含数字类型和八位字节字符串,因此我尝试使用字节切片作为值容器并unsafe.Pointer根据具体类型使用它。func test3() (total int64) {&nbsp; &nbsp; type A struct {&nbsp; &nbsp; &nbsp; &nbsp; t int32&nbsp; &nbsp; &nbsp; &nbsp; u []byte&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp; &nbsp; a := [...]A{{1, make([]byte, 8)}, {2, make([]byte, 8)}}&nbsp; &nbsp; *(*int32)(unsafe.Pointer(&a[0].u)) = 100&nbsp;&nbsp; &nbsp; *(*int16)(unsafe.Pointer(&a[1].u)) = 3&nbsp;&nbsp; &nbsp; for i := 0; i < 5000000000; i++ {&nbsp; &nbsp; &nbsp; &nbsp; p := &a[i%2]&nbsp; &nbsp; &nbsp; &nbsp; switch p.t {&nbsp; &nbsp; &nbsp; &nbsp; case 1:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; total += int64(*(*int32)(unsafe.Pointer(&p.u)))&nbsp; &nbsp; &nbsp; &nbsp; case 2:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; total += int64(*(*int16)(unsafe.Pointer(&p.u)))&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp;&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp; &nbsp; return}结果:$ go run union.go25750000000012.844752701s$ go run -compiler gccgo -gccgoflags -O3 union.go2575000000006.640667s它是最好的版本吗?
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go