golang 泛型预览

终于,”大道至简”的go,泛型终于合并到master分支上去了。那么来了,让我们来搞一下

首先需要从源码编译golang

省略,把CGO禁了就好编译了

写个泛型 MAX

package main

import "fmt"

func gMax[T interface {type int, float64}](a T, b T) T {
    if T(a) > T(b) {
        return T(a)
    }
    return T(b)
}

func main() {
    fmt.Printf("%T=%[1]v\n", gMax(1, 2))
    fmt.Printf("%T=%[1]v\n", gMax(1.0, 2.2))
    fmt.Printf("%T=%[1]v\n", gMax[int](3.0, 4.0))
}

运行参数

go run -gcflags="-G=3" main.go

结果

int=2
float64=2.2
int=4

-G=3 可以从 go tool compile -help , -Gaccept generic code

这样就能体验go的泛型了

跟java泛型区别 TODO

把多余的输出干掉,方便看汇编

func main() {
    gMax(1, 2)
    gMax(1.0, 2.2)
}

来,编译成汇编

go run -gcflags="-G=3 -S" main.go

结果

# command-line-arguments
"".main STEXT size=103 args=0x0 locals=0x20 funcid=0x0
	0x0000 00000 (/home/goroot/bin/main.go:10)	TEXT	"".main(SB), ABIInternal, $32-0
	0x0000 00000 (/home/goroot/bin/main.go:10)	MOVQ	(TLS), R14
	0x0009 00009 (/home/goroot/bin/main.go:10)	CMPQ	SP, 16(R14)
	0x000d 00013 (/home/goroot/bin/main.go:10)	PCDATA	$0, $-2
	0x000d 00013 (/home/goroot/bin/main.go:10)	JLS	93
	0x000f 00015 (/home/goroot/bin/main.go:10)	PCDATA	$0, $-1
	0x000f 00015 (/home/goroot/bin/main.go:10)	SUBQ	$32, SP
	0x0013 00019 (/home/goroot/bin/main.go:10)	MOVQ	BP, 24(SP)
	0x0018 00024 (/home/goroot/bin/main.go:10)	LEAQ	24(SP), BP
	0x001d 00029 (/home/goroot/bin/main.go:10)	FUNCDATA	$0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
	0x001d 00029 (/home/goroot/bin/main.go:10)	FUNCDATA	$1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
	0x001d 00029 (/home/goroot/bin/main.go:11)	MOVQ	$1, (SP)
	0x0025 00037 (/home/goroot/bin/main.go:11)	MOVQ	$2, 8(SP)
	0x002e 00046 (/home/goroot/bin/main.go:11)	PCDATA	$1, $0
    ## CALL
	0x002e 00046 (/home/goroot/bin/main.go:11)	CALL	"".gMax[int](SB)
	0x0033 00051 (/home/goroot/bin/main.go:12)	MOVSD	$f64.3ff0000000000000(SB), X0
	0x003b 00059 (/home/goroot/bin/main.go:12)	MOVSD	X0, (SP)
	0x0040 00064 (/home/goroot/bin/main.go:12)	MOVSD	$f64.400199999999999a(SB), X0
	0x0048 00072 (/home/goroot/bin/main.go:12)	MOVSD	X0, 8(SP)
    ## CALL
	0x004e 00078 (/home/goroot/bin/main.go:12)	CALL	"".gMax[float64](SB)
	0x0053 00083 (/home/goroot/bin/main.go:13)	MOVQ	24(SP), BP
	0x0058 00088 (/home/goroot/bin/main.go:13)	ADDQ	$32, SP
	0x005c 00092 (/home/goroot/bin/main.go:13)	RET
	0x005d 00093 (/home/goroot/bin/main.go:13)	NOP
	0x005d 00093 (/home/goroot/bin/main.go:10)	PCDATA	$1, $-1
	0x005d 00093 (/home/goroot/bin/main.go:10)	PCDATA	$0, $-2
	0x005d 00093 (/home/goroot/bin/main.go:10)	NOP
	0x0060 00096 (/home/goroot/bin/main.go:10)	CALL	runtime.morestack_noctxt(SB)
	0x0065 00101 (/home/goroot/bin/main.go:10)	PCDATA	$0, $-1
	0x0065 00101 (/home/goroot/bin/main.go:10)	JMP	0
	0x0000 64 4c 8b 34 25 00 00 00 00 49 3b 66 10 76 4e 48  dL.4%....I;f.vNH
	0x0010 83 ec 20 48 89 6c 24 18 48 8d 6c 24 18 48 c7 04  .. H.l$.H.l$.H..
	0x0020 24 01 00 00 00 48 c7 44 24 08 02 00 00 00 e8 00  $....H.D$.......
	0x0030 00 00 00 f2 0f 10 05 00 00 00 00 f2 0f 11 04 24  ...............$
	0x0040 f2 0f 10 05 00 00 00 00 f2 0f 11 44 24 08 e8 00  ...........D$...
	0x0050 00 00 00 48 8b 6c 24 18 48 83 c4 20 c3 0f 1f 00  ...H.l$.H.. ....
	0x0060 e8 00 00 00 00 eb 99                             .......
	rel 5+4 t=16 TLS+0
	rel 47+4 t=7 "".gMax[int]+0
	rel 55+4 t=15 $f64.3ff0000000000000+0
	rel 68+4 t=15 $f64.400199999999999a+0
	rel 79+4 t=7 "".gMax[float64]+0
	rel 97+4 t=7 runtime.morestack_noctxt+0
"".gMax[int] STEXT nosplit size=27 args=0x18 locals=0x0 funcid=0x0
    ## 声明
	0x0000 00000 (/home/goroot/bin/main.go:3)	TEXT	"".gMax[int](SB), NOSPLIT|ABIInternal, $0-24
	0x0000 00000 (/home/goroot/bin/main.go:3)	FUNCDATA	$0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
	0x0000 00000 (/home/goroot/bin/main.go:3)	FUNCDATA	$1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
	0x0000 00000 (/home/goroot/bin/main.go:4)	MOVQ	"".b+16(SP), AX
	0x0005 00005 (/home/goroot/bin/main.go:4)	MOVQ	"".a+8(SP), CX
	0x000a 00010 (/home/goroot/bin/main.go:4)	CMPQ	AX, CX
	0x000d 00013 (/home/goroot/bin/main.go:4)	JGE	21
	0x000f 00015 (/home/goroot/bin/main.go:5)	MOVQ	CX, "".~r2+24(SP)
	0x0014 00020 (/home/goroot/bin/main.go:5)	RET
	0x0015 00021 (/home/goroot/bin/main.go:7)	MOVQ	AX, "".~r2+24(SP)
	0x001a 00026 (/home/goroot/bin/main.go:7)	RET
	0x0000 48 8b 44 24 10 48 8b 4c 24 08 48 39 c8 7d 06 48  H.D$.H.L$.H9.}.H
	0x0010 89 4c 24 18 c3 48 89 44 24 18 c3                 .L$..H.D$..
"".gMax[float64] STEXT nosplit size=33 args=0x18 locals=0x0 funcid=0x0
    ## 声明
	0x0000 00000 (/home/goroot/bin/main.go:3)	TEXT	"".gMax[float64](SB), NOSPLIT|ABIInternal, $0-24
	0x0000 00000 (/home/goroot/bin/main.go:3)	FUNCDATA	$0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
	0x0000 00000 (/home/goroot/bin/main.go:3)	FUNCDATA	$1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
	0x0000 00000 (/home/goroot/bin/main.go:4)	MOVSD	"".a+8(SP), X0
	0x0006 00006 (/home/goroot/bin/main.go:4)	MOVSD	"".b+16(SP), X1
	0x000c 00012 (/home/goroot/bin/main.go:4)	UCOMISD	X1, X0
	0x0010 00016 (/home/goroot/bin/main.go:4)	JLS	25
	0x0012 00018 (/home/goroot/bin/main.go:5)	MOVSD	X0, "".~r2+24(SP)
	0x0018 00024 (/home/goroot/bin/main.go:5)	RET
	0x0019 00025 (/home/goroot/bin/main.go:7)	MOVSD	X1, "".~r2+24(SP)
	0x001f 00031 (/home/goroot/bin/main.go:7)	NOP
	0x0020 00032 (/home/goroot/bin/main.go:7)	RET
	0x0000 f2 0f 10 44 24 08 f2 0f 10 4c 24 10 66 0f 2e c1  ...D$....L$.f...
	0x0010 76 07 f2 0f 11 44 24 18 c3 f2 0f 11 4c 24 18 90  v....D$.....L$..
	0x0020 c3                                               .

emm,跟 Java 类型擦除不一样,go 似乎是通过代码生成来实现泛型的,运行效率可以保证了,编译产物增大也是可以接受吧。