您正在阅读和引用的代码只是具有一致文档的虚拟代码。内置函数内置于语言中,因此包含在代码处理步骤(编译器)中。
简化后发生的情况是:词法分析器将检测到 'append(...)
' as APPEND
令牌,解析器将翻译APPEND
,根据编码的情况/参数/环境,将代码编写为汇编并进行汇编。中间步骤——实施append
- 可以在编译器中找到here https://github.com/golang/go/blob/6327e8dc69c47d6355e2623cc491f0140d2563f5/src/cmd/compile/internal/gc/cgen.go#L2748.
会发生什么append
当查看示例程序的汇编时,可以最好地看到调用。考虑一下:
b := []byte{'a'}
b = append(b, 'b')
println(string(b), cap(b))
运行它将产生以下输出:
ab 2
The append
调用被转换为汇编,如下所示:
// create new slice object
MOVQ BX, "".b+120(SP) // BX contains data addr., write to b.addr
MOVQ BX, CX // store addr. in CX
MOVQ AX, "".b+128(SP) // AX contains len(b) == 1, write to b.len
MOVQ DI, "".b+136(SP) // DI contains cap(b) == 1, write to b.cap
MOVQ AX, BX // BX now contains len(b)
INCQ BX // BX++
CMPQ BX, DI // compare new length (2) with cap (1)
JHI $1, 225 // jump to grow code if len > cap
...
LEAQ (CX)(AX*1), BX // load address of newly allocated slice entry
MOVB $98, (BX) // write 'b' to loaded address
// grow code, call runtime.growslice(t *slicetype, old slice, cap int)
LEAQ type.[]uint8(SB), BP
MOVQ BP, (SP) // load parameters onto stack
MOVQ CX, 8(SP)
MOVQ AX, 16(SP)
MOVQ SI, 24(SP)
MOVQ BX, 32(SP)
PCDATA $0, $0
CALL runtime.growslice(SB) // call
MOVQ 40(SP), DI
MOVQ 48(SP), R8
MOVQ 56(SP), SI
MOVQ R8, AX
INCQ R8
MOVQ DI, CX
JMP 108 // jump back, growing done
正如你所看到的,没有CALL
调用函数的语句append
看得到。这是全面落实append
调用示例代码。使用不同参数的另一个调用will看起来不同(其他寄存器,不同的参数取决于切片类型等)。