Go中func append的实现在哪里? [英] Where is the implementation of func append in Go?
问题描述
我对go非常感兴趣,并尝试阅读go函数的实现.我发现其中一些功能在那里没有实现.
I'm very interested in go, and trying to read go function's implementations. I found some of these function doesn't have implementations there.
例如追加或调用:
// The append built-in function appends elements to the end of a slice. If
// it has sufficient capacity, the destination is resliced to accommodate the
// new elements. If it does not, a new underlying array will be allocated.
// Append returns the updated slice. It is therefore necessary to store the
// result of append, often in the variable holding the slice itself:
// slice = append(slice, elem1, elem2)
// slice = append(slice, anotherSlice...)
// As a special case, it is legal to append a string to a byte slice, like this:
// slice = append([]byte("hello "), "world"...)
func append(slice []Type, elems ...Type) []Type
// call calls fn with a copy of the n argument bytes pointed at by arg.
// After fn returns, reflectcall copies n-retoffset result bytes
// back into arg+retoffset before returning. If copying result bytes back,
// the caller must pass the argument frame type as argtype, so that
// call can execute appropriate write barriers during the copy.
func call(argtype *rtype, fn, arg unsafe.Pointer, n uint32, retoffset uint32)
似乎没有调用C代码,因为使用cgo需要一些特殊的注释.这些功能的实现在哪里?
It seems not calling a C code, because using cgo needs some special comments. Where is these function's implementations?
推荐答案
您正在阅读和引用的代码只是具有一致文档的伪代码.内置函数很好地内置在该语言中,因此包含在代码处理步骤(编译器)中.
The code you are reading and citing is just dummy code to have consistent documentation. The built-in functions are, well, built into the language and, as such, are included in the code processing step (the compiler).
简化的操作是:lexer将检测到 append(...)
'作为 APPEND
令牌,解析器将翻译 APPEND
,具体取决于根据代码的环境/参数/环境,将代码编写为汇编和汇编.中间步骤- append
的实现-可以在编译器
Simplified what happens is: lexer will detect 'append(...)
' as APPEND
token, parser will translate APPEND
, depending on the circumstances/parameters/environment to code, code is written as assembly and assembled. The middle step - the implementation of append
- can be found in the compiler here.
在查看示例程序的程序集时,最好能看到 append
调用发生了什么.考虑一下:
What happens to an append
call is best seen when looking at the assembly of an example program. Consider this:
b := []byte{'a'}
b = append(b, 'b')
println(string(b), cap(b))
运行它会产生以下输出:
Running it will yield the following output:
ab 2
将 append
调用转换为如下形式的程序集:
The append
call is translated to assembly like this:
// 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
如您所见,看不到名为 append
的函数的 CALL
语句.这是示例代码中 append
调用的完整实现.另一个具有不同参数 的调用的外观会有所不同(其他寄存器,取决于切片类型的不同参数,等等).
As you can see, no CALL
statement to a function called append
can be seen. This is the full implementation of the append
call in the example code. Another call with different parameters will look differently (other registers, different parameters depending on the slice type, etc.).
这篇关于Go中func append的实现在哪里?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!