Go中的func实现在哪里附加?

use*_*771 4 go

我非常感兴趣,并尝试阅读go函数的实现.我发现其中一些功能没有实现.

如追加或致电:

// 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)
Run Code Online (Sandbox Code Playgroud)

它似乎没有调用C代码,因为使用cgo需要一些特殊的注释.这些功能的实现在哪里?

nem*_*emo 11

您正在阅读和引用的代码只是具有一致文档的虚拟代码.内置函数很好地构建在语言中,因此包含在代码处理步骤(编译器)中.

简化会发生的事情是:lexer将检测' append(...)'作为APPEND令牌,解析器将转换APPEND,根据环境/参数/环境来编码,代码被编写为汇编和汇编.中间步骤 - 实现append- 可以在这里的编译器中找到.

append在查看示例程序的程序集时,最好看到调用会发生什么.考虑一下:

b := []byte{'a'}
b = append(b, 'b')
println(string(b), cap(b))
Run Code Online (Sandbox Code Playgroud)

运行它将产生以下输出:

ab 2
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

如您所见,无法看到所CALL调用函数的语句append.这是append示例代码中调用的完整实现.具有不同参数的另一个调用看起来不同(其他寄存器,根据切片类型的不同参数等).