Go学习系列:" _ "空标识符的本质及小技巧

2018-10-31  本文已影响0人  沙漠中的猴
package main

//go:noinline
//go:nosplit
func test() (int, int) {
    return 1, 2
}

func main() {
    x := 100
    _ = x
    a, _ := test()
    println(a)
}

对于这个空标识符,编译器是如何处理的?什么类型的变量都可以接收?
我们反汇编来看下具体的处理细节。

root@000d3fada0b3:~/go/src/test# go build -gcflags "-N -l"
root@000d3fada0b3:~/go/src/test# go tool objdump -S -s "main\.main" test
TEXT main.main(SB) /root/go/src/test/main.go
func main() {
  0x44c180      64488b0c25f8ffffff  MOVQ FS:0xfffffff8, CX
  0x44c189      483b6110        CMPQ 0x10(CX), SP
  0x44c18d      7651            JBE 0x44c1e0
  0x44c18f      4883ec30        SUBQ $0x30, SP
  0x44c193      48896c2428      MOVQ BP, 0x28(SP)
  0x44c198      488d6c2428      LEAQ 0x28(SP), BP
    x := 100
  0x44c19d      48c744241064000000  MOVQ $0x64, 0x10(SP)
    a, _ := test()
  0x44c1a6      e8a5ffffff      CALL main.test(SB)
  0x44c1ab      488b0424        MOVQ 0(SP), AX
  0x44c1af      4889442420      MOVQ AX, 0x20(SP)
  0x44c1b4      4889442418      MOVQ AX, 0x18(SP)
    println(a)
  0x44c1b9      e84259fdff      CALL runtime.printlock(SB)
  0x44c1be      488b442418      MOVQ 0x18(SP), AX
  0x44c1c3      48890424        MOVQ AX, 0(SP)
  0x44c1c7      e8b460fdff      CALL runtime.printint(SB)
  0x44c1cc      e8bf5bfdff      CALL runtime.printnl(SB)
  0x44c1d1      e8aa59fdff      CALL runtime.printunlock(SB)
}
  0x44c1d6      488b6c2428      MOVQ 0x28(SP), BP
  0x44c1db      4883c430        ADDQ $0x30, SP
  0x44c1df      c3          RET
func main() {
  0x44c1e0      e88b83ffff      CALL runtime.morestack_noctxt(SB)
  0x44c1e5      eb99            JMP main.main(SB)

通过上面的输出信息可以看到,_ = x并没有被编译器处理,直接被忽略了。

   a, _ := test()
  0x44c1a6      e8a5ffffff      CALL main.test(SB)
  0x44c1ab      488b0424        MOVQ 0(SP), AX

这个空标识符也是仅仅处理了一个变量a。空标识符也是被忽略掉了。

编译器会忽略空标识符赋值。

小技巧

Go里面很难知道,一个变量是否实现了某个接口。我们可以通过_空标识符来检查是否实现了某个对应的接口。
例:

package main

type Xer interface {
    A()
}
type X int

// func (x X) A() {}
var _ Xer = X(0)

func main() {

}

我们可以通过对空标识符赋值,来让编译器帮我们检查变量X是否实现了Xer接口

root@000d3fada0b3:~/go/src/test# go build -gcflags "-N -l"
# test
./main.go:9:5: cannot use X(0) (type X) as type Xer in assignment:
    X does not implement Xer (missing A method)

总结

编译器会忽略空标识符赋值。
可以通过空标识符来让编译器帮我们检测一个变量是否实现了某个接口。

上一篇下一篇

猜你喜欢

热点阅读