为什么 Go 标准库中有些函数只有签名,没有函数体?
本文内容纲要:
-函数签名使用Go,然后通过该包中的汇编文件来实现它
-通过//go:linkname指令来实现
如果你看过Go语言标准库,应该有见到过,有一些函数只有签名,没有函数体。你有没有感觉到很奇怪?这到底是怎么回事?我们自己可以这么做吗?本文就来解密它。
首先,函数肯定得有实现,没有函数体,一定是在其他某个地方。Go中一般有两种形式。
函数签名使用Go,然后通过该包中的汇编文件来实现它
比如,在标准库sync/atomic
包中的函数基本只有函数签名。比如:atomic.StoreInt32
//StoreInt32atomicallystoresvalinto*addr.
funcStoreInt32(addr*int32,valint32)
它的函数实现在哪呢?其实只要稍微留意一下发现该目录下有一个文件:asm.s,它提供了具体的实现,即通过汇编来实现:
TEXT·StoreInt32(SB),NOSPLIT,$0
JMPruntime∕internal∕atomic·Store(SB)
具体的实现,在runtime∕internal
文件夹中,有兴趣你可以打开asm_amd64.s看看。
很明显,这种方式一方面会是效率的考虑,另一方面,有一些代码只能汇编实现。
以上方式,你自己也可以尝试。比如实现一个Sum(a,bint)int
。欢迎评论给出你的代码。
通过//go:linkname指令来实现
比如,在标准库time
包中的Sleep
函数:
//Sleeppausesthecurrentgoroutineforatleastthedurationd.
//AnegativeorzerodurationcausesSleeptoreturnimmediately.
funcSleep(dDuration)
它的实现在哪里呢?在time包中并没有找到相应的汇编文件。
按照Go源码的风格,这时候一般需要去runtime
包中找。我们会找到time.go,其中有一个函数:
//timeSleepputsthecurrentgoroutinetosleepforatleastnsnanoseconds.
//go:linknametimeSleeptime.Sleep
functimeSleep(nsint64){
...
}
这就是我们要找的time.Sleep
的实现。
如果你有认真跟着学习「每日一学」,对于//go:linkname
应该不陌生,这里的关键就在于这个指令,它的格式是:
//go:linkname函数名包名.函数名
因此我们在遇到函数没有实现,但汇编又不存在时,可以通过尝试搜索:go:linknamexxxxx.xxx
的形式来找,比如time.Sleep
就可以通过//go:linknametimeSleeptime.Sleep
来查找具体实现在哪。
这里面要提示一点,使用//go:linkname
,必须导入unsafe
包,所以,有时候会见到:import_"unsafe"
这样的代码。
一般来说,我们自己的代码不会使用这样的方式,但你会写一个示例试试吗?欢迎评论给出你的代码。
另外,想想为什么time.Sleep
的实现要这么搞?
转载自:
为什么Go标准库中有些函数只有签名,没有函数体?
本文内容总结:函数签名使用Go,然后通过该包中的汇编文件来实现它,通过//go:linkname指令来实现,
原文链接:https://www.cnblogs.com/itbsl/p/11410857.html