<kbd id="5sdj3"></kbd>
<th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>

    卷起來(lái)!Go泛型是怎么實(shí)現(xiàn)的?

    共 20336字,需瀏覽 41分鐘

     ·

    2021-09-02 20:02

    Go 1.17中你就可以使用泛型了,可以參考我3月份的文章:Go 泛型嘗鮮, 編譯的時(shí)候需要加-gcflags=-G=3參數(shù),而當(dāng)前master分支,默認(rèn)已經(jīng)支持泛型,不需要加-G=3參數(shù)了。

    你可以通過(guò)下面的步驟嘗試go最新分支:

    go get golang.org/dl/gotip
    gotip download

    編譯代碼的時(shí)候使用gotip替換go命令即可。

    隨著Go 1.17的發(fā)布,最近也涌現(xiàn)了很多的介紹Go泛型的文章,基本上都是簡(jiǎn)單介紹的文章。

    最近Go泛型的變化是增加了兩個(gè)操作符: ~|

    • an approximation element~T restricts to all types whose underlying type is T: 代表底層類型是T
    • a union element T1 | T2 | ... restricts to any of the listed elements: 代表,類型列表之一。這些不是我想介紹的內(nèi)容,今天我肝一篇介紹Go泛型實(shí)現(xiàn)原理的文章,介紹Go泛型實(shí)現(xiàn)的方案。

    對(duì)于一個(gè)函數(shù)func Echo[T any](t T){},Go編譯器到底編譯成了什么代碼?

    簡(jiǎn)單的說(shuō),當(dāng)前Go泛型實(shí)現(xiàn)的方案和下圖中的方案一樣:

    在國(guó)內(nèi)的老破小小區(qū)的樓道中常見(jiàn)的一種高科技印刷技術(shù),通過(guò)一個(gè)鏤花模板,為每一種類型生成特化的類型,這個(gè)術(shù)語(yǔ)叫做stenciling

    但是如果再說(shuō)多一點(diǎn),那么就應(yīng)該從 Taylor和Griesemer說(shuō)起。

    Go泛型提案中關(guān)于泛型實(shí)現(xiàn)的介紹

    Go的泛型有別于其它語(yǔ)言的方案,在Go語(yǔ)言中泛型叫做Type Parameter(類型參數(shù)).

    Taylor和Griesemer的提案Type Parameters Proposal更多的是泛型呈現(xiàn)形式和影響的思考,對(duì)具體的實(shí)現(xiàn)涉及甚少。

    無(wú)論什么編程語(yǔ)言,根據(jù)Russ Cox的觀察,實(shí)現(xiàn)泛型至少要面對(duì)下面三條困境之一,那還是在2009年:

    • 拖累程序員:比如C語(yǔ)言,增加了程序員的負(fù)擔(dān),需要曲折的實(shí)現(xiàn),但是不對(duì)增加語(yǔ)言的復(fù)雜性
    • 拖累編譯器: 比如C++編程語(yǔ)言,增加了編譯器的負(fù)擔(dān),可能會(huì)產(chǎn)生很多冗余的代碼,重復(fù)的代碼還需要編譯器斟酌刪除,編譯的文件可能非常大。Rust的泛型也屬于這一類。
    • 拖累執(zhí)行時(shí)間:比如Java,將一些裝箱成Object,進(jìn)行類型擦除。雖然代碼沒(méi)啥冗余了,空間節(jié)省了,但是需要裝箱拆箱操作,代碼效率低。很顯然, Go語(yǔ)言至簡(jiǎn)的設(shè)計(jì)哲學(xué)讓它的泛型實(shí)現(xiàn)不會(huì)選擇增加程序員的負(fù)擔(dān)的道路,所以它會(huì)在第二和第三種方案中做選擇。雖然提案中沒(méi)有最終說(shuō)明它選擇了哪種方案,但是從實(shí)際編譯的代碼可以看出,它選擇的是第二種方案。

    三個(gè)方案

    Keith H. Randall, MIT的博士,現(xiàn)在在Google/Go team做泛型方面的開(kāi)發(fā),提出了Go泛型實(shí)現(xiàn)的三個(gè)方案:

    1.字典

    在編譯時(shí)生成一組實(shí)例化的字典,在實(shí)例話一個(gè)泛型函數(shù)的時(shí)候會(huì)使用字典進(jìn)行蠟印(stencile)。

    當(dāng)為泛型函數(shù)生成代碼的時(shí)候,會(huì)生成唯一的一塊代碼,并且會(huì)在參數(shù)列表中增加一個(gè)字典做參數(shù),就像方法會(huì)把receiver當(dāng)成一個(gè)參數(shù)傳入。字典包含為類型參數(shù)實(shí)例化的類型信息。

    字典在編譯時(shí)生成,存放在只讀的data section中。

    當(dāng)然字段可以當(dāng)成第一個(gè)參數(shù),或者最后一個(gè)參數(shù),或者放入一個(gè)獨(dú)占的寄存器。

    當(dāng)然這種方案還有依稀問(wèn)題,比如字典遞歸的問(wèn)題,更重要的是,它對(duì)性能可能有比較大的影響,比如一個(gè)實(shí)例化類型int, x=y可能通過(guò)寄存器復(fù)制就可以了,但是泛型必須通過(guò)memmove

    2.蠟印(Stenciling)

    或者翻譯成用模板印等。

    就像下面的動(dòng)圖一樣,同一個(gè)泛型函數(shù),為每一個(gè)實(shí)例化的類型參數(shù)生成一套獨(dú)立的代碼,感覺(jué)和rust的泛型特化一樣。

    這種方案和上面的字典方案正好相反。

    比如下面一個(gè)泛型方法:

    func f[T1, T2 any](x int, y T1) T2 {
        ...
    }

    如果有兩個(gè)不同的類型實(shí)例化的調(diào)用:

    var a float64 = f[int, float64](7, 8.0)
    var b struct{f int} = f[complex128, struct{f int}](3, 1+1i)

    那么這個(gè)方案會(huì)生成兩套代碼:

    func f1(x int, y int) float64 {
        ... identical bodies ...
    }
    func f2(x int, y complex128) struct{f int} {
        ... identical bodies ...
    }

    因?yàn)榫幾gf時(shí)是不知道它的實(shí)例化類型的,只有在調(diào)用它時(shí)才知道它的實(shí)例化的類型,所以需要在調(diào)用時(shí)編譯f。對(duì)于相同實(shí)例化類型的多個(gè)調(diào)用,同一個(gè)package下編譯器可以識(shí)別出來(lái)是一樣的,只生成一個(gè)代碼就可以了,但是不同的package就不簡(jiǎn)單了,這些函數(shù)表標(biāo)記為DUPOK,所以鏈接器會(huì)丟掉重復(fù)的函數(shù)實(shí)現(xiàn)。

    這種策略需要更多的編譯時(shí)間,因?yàn)樾枰幾g泛型函數(shù)多次。因?yàn)閷?duì)于同一個(gè)泛型函數(shù),每種類型需要單獨(dú)的一份編譯的代碼,如果類型非常多,編譯的文件可能非常大,而且性能也比較差。

    3.混合方案(GC Shape Stenciling)

    混合前面的兩種方案。

    對(duì)于實(shí)例類型的shape相同的情況,只生成一份代碼,對(duì)于shape類型相同的類型,使用字典區(qū)分類型的不同行為。

    這種方案介于前兩者之間。

    啥叫shape?

    類型的shape是它對(duì)內(nèi)存分配器/垃圾回收器呈現(xiàn)的方式,包括它的大小、所需的對(duì)齊方式、以及類型哪些部分包含指針。

    每一個(gè)唯一的shape會(huì)產(chǎn)生一份代碼,每份代碼攜帶一個(gè)字典,包含了實(shí)例化類型的信息。

    這種方案的問(wèn)題是到底能帶來(lái)多大的收益,它會(huì)變得有多慢,以及其它的一些問(wèn)題。

    從當(dāng)前的反編譯的代碼看,當(dāng)前Go采用的是第二種方案,盡管名稱中已經(jīng)帶了shapedict的標(biāo)志,或許,Go的泛型方案還在進(jìn)化之中,進(jìn)化到第三種方案或者其它方案也不是沒(méi)有可能。

    接下來(lái)我們看一個(gè)例子,看看Go泛型的方案是怎么實(shí)現(xiàn)的。

    例子

    下面是一個(gè)簡(jiǎn)單的例子,有一個(gè)泛型函數(shù)func echo[T any](t T) string {return fmt.Sprintf("%v", t)},使用不同的幾種實(shí)例化類型去調(diào)用它,并且使用shape一樣的int32uint32做為實(shí)例化類型。

    package generic
    import (
     "fmt"
     "time"
    )
    func echo[T any](t T) string {
     return fmt.Sprintf("%v", t)
    }
    func Test() {
     echo(0)
     echo(int32(0))
     echo(uint32(0))
     echo(uint64(0))
     echo("hello")
     echo(struct{}{})
     echo(time.Now())
    }

    反編譯后代碼非常長(zhǎng),精簡(jiǎn)如下。編譯的時(shí)候禁止優(yōu)化和內(nèi)聯(lián),否則實(shí)例化的代碼內(nèi)聯(lián)后看不到效果了。

    可以看到函數(shù)echo編譯成了不同的函數(shù):"".echo[.shape.int]"".echo[.shape.int32]、"".echo[.shape.uint32]、"".echo[.shape.uint64]、"".echo[.shape.string]、"".echo[.shape.struct{}]、"".echo[.shape.struct{ time.wall uint64; time.ext int64; time.loc *time.Location }]不同的函數(shù),即使shape一樣的類型(int32、uint32)。調(diào)用這些函數(shù)時(shí),是通過(guò)""..dict.echo[uint64]這種方式調(diào)用的。

    所以我謹(jǐn)慎懷疑,Go的泛型方式在逐步的向第三種方案進(jìn)化。

    # command-line-arguments
    "".Test STEXT size=185 args=0x0 locals=0x48 funcid=0x0
     0x0000 00000 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:12) TEXT "".Test(SB), ABIInternal, $72-0
     "".Test STEXT size=185 args=0x0 locals=0x48 funcid=0x0
     0x0000 00000 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:12) TEXT "".Test(SB), ABIInternal, $72-0
     0x0000 00000 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:12) CMPQ SP, 16(R14)
     0x0004 00004 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:12) PCDATA $0, $-2
     0x0004 00004 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:12) JLS 175
     0x000a 00010 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:12) PCDATA $0, $-1
     0x000a 00010 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:12) SUBQ $72, SP
     0x000e 00014 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:12) MOVQ BP, 64(SP)
     0x0013 00019 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:12) LEAQ 64(SP), BP
     0x0018 00024 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:12) FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
     0x0018 00024 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:12) FUNCDATA $1, gclocals·54241e171da8af6ae173d69da0236748(SB)
     0x0018 00024 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:13) LEAQ ""..dict.echo[int](SB), AX
     0x001f 00031 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:13) XORL BX, BX
     0x0021 00033 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:13) PCDATA $1$0
     0x0021 00033 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:13) CALL "".echo[.shape.int](SB)
     0x0026 00038 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:14) LEAQ ""..dict.echo[int32](SB), AX
     0x002d 00045 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:14) XORL BX, BX
     0x002f 00047 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:14) CALL "".echo[.shape.int32](SB)
     0x0034 00052 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:15) LEAQ ""..dict.echo[uint32](SB), AX
     0x003b 00059 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:15) XORL BX, BX
     0x003d 00061 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:15) NOP
     0x0040 00064 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:15) CALL "".echo[.shape.uint32](SB)
     0x0045 00069 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:16) LEAQ ""..dict.echo[uint64](SB), AX
     0x004c 00076 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:16) XORL BX, BX
     0x004e 00078 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:16) CALL "".echo[.shape.uint64](SB)
     0x0053 00083 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:17) LEAQ ""..dict.echo[string](SB), AX
     0x005a 00090 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:17) LEAQ go.string."hello"(SB), BX
     0x0061 00097 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:17) MOVL $5, CX
     0x0066 00102 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:17) CALL "".echo[.shape.string](SB)
     0x006b 00107 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:18) LEAQ ""..dict.echo[struct{}](SB), AX
     0x0072 00114 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:18) CALL "".echo[.shape.struct{}](SB)
     0x0077 00119 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:19) CALL time.Now(SB)
     0x007c 00124 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:19) MOVQ AX, ""..autotmp_0+40(SP)
     0x0081 00129 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:19) MOVQ BX, ""..autotmp_0+48(SP)
     0x0086 00134 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:19) MOVQ CX, ""..autotmp_0+56(SP)
     0x008b 00139 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:19) MOVQ CX, DI
     0x008e 00142 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:19) MOVQ BX, CX
     0x0091 00145 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:19) MOVQ AX, BX
     0x0094 00148 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:19) LEAQ ""..dict.echo[time.Time](SB), AX
     0x009b 00155 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:19) NOP
     0x00a0 00160 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:19) CALL "".echo[.shape.struct{ time.wall uint64; time.ext int64; time.loc *time.Location }](SB)
     0x00a5 00165 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:20) MOVQ 64(SP), BP
     0x00aa 00170 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:20) ADDQ $72, SP
     0x00ae 00174 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:20) RET
     0x00af 00175 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:20) NOP
     0x00af 00175 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:12) PCDATA $1, $-1
     0x00af 00175 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:12) PCDATA $0, $-2
     0x00af 00175 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:12) CALL runtime.morestack_noctxt(SB)
     0x00b4 00180 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:12) PCDATA $0, $-1
     0x00b4 00180 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:12) JMP 0
        .................
    "".echo[.shape.int] STEXT dupok size=268 args=0x10 locals=0x88 funcid=0x0
     0x0000 00000 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:8) TEXT "".echo[.shape.int](SB), DUPOK|ABIInternal, $136-16
     .................
     0x00c2 00194 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:9) MOVQ DI, SI
     0x00c5 00197 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:9) PCDATA $1$0
     0x00c5 00197 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:9) CALL fmt.Sprintf(SB)
        .................
    "".echo[.shape.int32] STEXT dupok size=266 args=0x10 locals=0x88 funcid=0x0
     0x0000 00000 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:8) TEXT "".echo[.shape.int32](SB), DUPOK|ABIInternal, $136-16
     .................
     0x00bd 00189 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:9) MOVL $1, DI
     0x00c2 00194 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:9) MOVQ DI, SI
     0x00c5 00197 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:9) PCDATA $1$0
     0x00c5 00197 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:9) CALL fmt.Sprintf(SB)
        .................
    "".echo[.shape.uint32] STEXT dupok size=266 args=0x10 locals=0x88 funcid=0x0
     0x0000 00000 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:8) TEXT "".echo[.shape.uint32](SB), DUPOK|ABIInternal, $136-16
     .................
     0x00c5 00197 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:9) PCDATA $1$0
     0x00c5 00197 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:9) CALL fmt.Sprintf(SB)
        .................
    "".echo[.shape.uint64] STEXT dupok size=268 args=0x10 locals=0x88 funcid=0x0
     0x0000 00000 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:8) TEXT "".echo[.shape.uint64](SB), DUPOK|ABIInternal, $136-16
     .................
     0x00c2 00194 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:9) MOVQ DI, SI
     0x00c5 00197 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:9) PCDATA $1$0
     0x00c5 00197 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:9) CALL fmt.Sprintf(SB)
        .................
    "".echo[.shape.string] STEXT dupok size=295 args=0x18 locals=0x88 funcid=0x0
     0x0000 00000 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:8) TEXT "".echo[.shape.string](SB), DUPOK|ABIInternal, $136-24
     .................
     0x00d6 00214 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:9) PCDATA $1$2
     0x00d6 00214 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:9) CALL fmt.Sprintf(SB)
        .................
    "".echo[.shape.struct{}] STEXT dupok size=208 args=0x8 locals=0x88 funcid=0x0
     0x0000 00000 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:8) TEXT "".echo[.shape.struct{}](SB), DUPOK|ABIInternal, $136-8
     .................
     0x0093 00147 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:9) PCDATA $1$0
     0x0093 00147 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:9) CALL fmt.Sprintf(SB)
        .................
     0x00cb 00203 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:8) JMP 0
     .................
    "".echo[.shape.struct{ time.wall uint64; time.ext int64; time.loc *time.Location }] STEXT dupok size=364 args=0x20 locals=0xa0 funcid=0x0
     0x0000 00000 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:8) TEXT "".echo[.shape.struct{ time.wall uint64; time.ext int64; time.loc *time.Location }](SB), DUPOK|ABIInternal, $160-32
     .................
     0x00c5 00197 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:9) CMPL runtime.writeBarrier(SB), $0
     0x00cc 00204 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:9) JEQ 208
     0x00ce 00206 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:9) JMP 214
     0x00d0 00208 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:9) MOVQ AX, 8(CX)
     0x00d4 00212 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:9) JMP 221
     0x00d6 00214 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:9) CALL runtime.gcWriteBarrier(SB)
     .................
     0x0167 00359 (/Users/chaoyuepan/go/src/github.com/smallnest/study/type_parameter/generic/generic.go:8) JMP 0
     
    ...............
    "".echo[.shape.string].stkobj SRODATA static size=32
     .......
    "".echo[.shape.string].arginfo1 SRODATA static dupok size=9
     .......           ..........
    "".echo[.shape.struct{}].stkobj SRODATA static size=32
     .......
    "".echo[.shape.struct{}].arginfo1 SRODATA static dupok size=5
     .......
    "".echo[.shape.struct{ time.wall uint64; time.ext int64; time.loc *time.Location }].stkobj SRODATA static size=56
     ......
    "".echo[.shape.struct{ time.wall uint64; time.ext int64; time.loc *time.Location }].arginfo1 SRODATA static dupok size=11
     0x0000 00 08 fe 08 08 10 08 18 08 fd ff                 ...........

    泛型的性能 寫一個(gè)簡(jiǎn)單的benchmark程序,沒(méi)看到明顯的性能變化。

    package bench_test
    import (
     "fmt"
        "testing"
    )
    func BenchmarkAdd_Generic(b *testing.B) {
     for i := 0; i < b.N; i++ {
      add(i, i)
     }
    }
    func BenchmarkAdd_NonGeneric(b *testing.B) {
     for i := 0; i < b.N; i++ {
      addInt(i, i)
     }
    }
    type Addable interface {
     int
    }
    func add[T Addable](a, b T) T {
     return a + b
    }
    func addInt(a, b int) int {
     return a + b
    }
    func main() {
     fmt.Println(add(1, 2))
     fmt.Println(addInt(1, 2))
    }

    參考文檔


    • https://github.com/golang/proposal/blob/master/design/generics-implementation-dictionaries.md
    • https://github.com/golang/proposal/blob/master/design/generics-implementation-gcshape.md
    • https://github.com/golang/proposal/blob/master/design/generics-implementation-stenciling.md
    • https://github.com/golang/proposal/blob/master/design/43651-type-parameters.md
    • https://docs.google.com/document/d/1vrAy9gMpMoS3uaVphB32uVXX4pi-HnNjkMEgyAHX4N4/view#



    想要了解關(guān)于 Go 的更多資訊,還可以通過(guò)掃描的方式,進(jìn)群一起探討哦~


    瀏覽 66
    點(diǎn)贊
    評(píng)論
    收藏
    分享

    手機(jī)掃一掃分享

    分享
    舉報(bào)
    評(píng)論
    圖片
    表情
    推薦
    點(diǎn)贊
    評(píng)論
    收藏
    分享

    手機(jī)掃一掃分享

    分享
    舉報(bào)

    <kbd id="5sdj3"></kbd>
    <th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>
    天天干,天天干 | 日韩高清一级免费 | 国产一级婬乱片免费 | 欧美成人在线视频网站 | 國產精品77777777777 |