首页 只有函数签名没有函数体的Go函数
文章
取消

只有函数签名没有函数体的Go函数

阅读 Go 源码时,我们可能经常看到只有签名(函数的第一行称为函数签名,它定义了函数的输入和输出类型)而没有实现的函数,如:

1
2
3
4
5
// src/time/sleep.go

// Sleep pauses the current goroutine for at least the duration d.
// A negative or zero duration causes Sleep to return immediately.
func Sleep(d Duration)

看上去很奇怪,没有实现?不可能的。

上面的情况,有两种可能实现:

笔者代码环境为 MacOS,go 1.19.2

函数是在汇编文件中实现的

以 LoadUint32 为例:

1
2
3
4
// src/sync/atomic/doc.go

// LoadUint32 atomically loads *addr.
func LoadUint32(addr *uint32) (val uint32)

在同目录下的 asm.s 中它是这样实现的:

1
2
3
// src/syc/atomic/asm.s
TEXT ·LoadUint32(SB),NOSPLIT,$0
	JMP	runtime∕internal∕atomic·Load(SB)

可以看到它的实现在 runtime∕internal∕atomic·Load(SB)

目录 src/runtime/internal/atomic 下有不同平台的汇编代码,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ ll /usr/local/go/src/runtime/internal/atomic/*.s
-rw-r--r--  1 root  wheel   5.1K Oct  1 02:17 /usr/local/go/src/runtime/internal/atomic/atomic_386.s
-rw-r--r--  1 root  wheel   4.0K Oct  1 02:17 /usr/local/go/src/runtime/internal/atomic/atomic_amd64.s
-rw-r--r--  1 root  wheel   5.3K Oct  1 02:17 /usr/local/go/src/runtime/internal/atomic/atomic_arm.s
-rw-r--r--  1 root  wheel   6.5K Oct  1 02:17 /usr/local/go/src/runtime/internal/atomic/atomic_arm64.s
-rw-r--r--  1 root  wheel   5.1K Oct  1 02:17 /usr/local/go/src/runtime/internal/atomic/atomic_loong64.s
-rw-r--r--  1 root  wheel   6.1K Oct  1 02:17 /usr/local/go/src/runtime/internal/atomic/atomic_mips64x.s
-rw-r--r--  1 root  wheel   4.3K Oct  1 02:17 /usr/local/go/src/runtime/internal/atomic/atomic_mipsx.s
-rw-r--r--  1 root  wheel   6.4K Oct  1 02:17 /usr/local/go/src/runtime/internal/atomic/atomic_ppc64x.s
-rw-r--r--  1 root  wheel   6.1K Oct  1 02:17 /usr/local/go/src/runtime/internal/atomic/atomic_riscv64.s
-rw-r--r--  1 root  wheel   5.9K Oct  1 02:17 /usr/local/go/src/runtime/internal/atomic/atomic_s390x.s
-rw-r--r--  1 root  wheel   269B Oct  1 02:17 /usr/local/go/src/runtime/internal/atomic/atomic_wasm.s
-rw-r--r--  1 root  wheel   3.1K Oct  1 02:17 /usr/local/go/src/runtime/internal/atomic/sys_linux_arm.s
-rw-r--r--  1 root  wheel   1.3K Oct  1 02:17 /usr/local/go/src/runtime/internal/atomic/sys_nonlinux_arm.s

我选择了 atomic_arm64.s ,里面有 .Load(SB) 的实现:

1
2
3
4
5
6
7
8
// src/runtime/internal/atomic/atomic_arm64.s

// uint32 ·Load(uint32 volatile* addr)
TEXT ·Load(SB),NOSPLIT,$0-12
	MOVD	ptr+0(FP), R0
	LDARW	(R0), R0
	MOVW	R0, ret+8(FP)
	RET

对于有些函数,Go 选择汇编代码来实现一方面是为了考虑效率,另一方面可能是有的功能只能用汇编来实现。

通过 //go:linkname 链接实现

比如下面这个函数:

1
2
3
4
// src/time/time.go 

// Provided by package runtime.
func now() (sec int64, nsec int32, mono int64)

它是由下面这个函数通过 //go:linkname time_now time.now 链接到的:

1
2
3
4
5
6
7
// src/runtime/timestub.go

//go:linkname time_now time.now
func time_now() (sec int64, nsec int32, mono int64) {
	sec, nsec = walltime()
	return sec, nsec, nanotime()
}
本文由作者按照 CC BY 4.0 进行授权