为什么 Go 标准库中有些函数只有签名,没有函数体?
如果你看过 Go 语言标准库,应该有见到过,有一些函数只有签名,没有函数体。你有没有感觉到很奇怪?这到底是怎么回事?我们自己可以这么做吗?本文就来解密它。
首先,函数肯定得有实现,没有函数体,一定是在其他某个地方。Go 中一般有两种形式。
函数签名使用Go,然后通过该包中的汇编文件来实现它
比如,在标准库 sync/atomic 包中的函数基本只有函数签名。比如:atomic.StoreInt32
// StoreInt32 atomically stores val into *addr.
func StoreInt32(addr *int32, val int32)
它的函数实现在哪呢?其实只要稍微留意一下发现该目录下有一个文件:asm.s,它提供了具体的实现,即通过汇编来实现:
TEXT ·StoreInt32(SB),NOSPLIT,$0
    JMP    runtime∕internal∕atomic·Store(SB)
具体的实现,在 runtime∕internal 文件夹中,有兴趣你可以打开 asm_amd64.s 看看。
很明显,这种方式一方面会是效率的考虑,另一方面,有一些代码只能汇编实现。
以上方式,你自己也可以尝试。比如实现一个 Sum(a, b int) int。欢迎评论给出你的代码。
通过//go:linkname指令来实现
比如,在标准库 time 包中的 Sleep 函数:
// 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)
它的实现在哪里呢?在 time 包中并没有找到相应的汇编文件。
按照 Go 源码的风格,这时候一般需要去 runtime 包中找。我们会找到 time.go,其中有一个函数:
// timeSleep puts the current goroutine to sleep for at least ns nanoseconds.
//go:linkname timeSleep time.Sleep
func timeSleep(ns int64) {
    ...
}
这就是我们要找的 time.Sleep 的实现。
如果你有认真跟着学习「每日一学」,对于 //go:linkname 应该不陌生,这里的关键就在于这个指令,它的格式是:
//go:linkname 函数名 包名.函数名
因此我们在遇到函数没有实现,但汇编又不存在时,可以通过尝试搜索:go:linkname xxx xx.xxx 的形式来找,比如 time.Sleep 就可以通过 //go:linkname timeSleep time.Sleep 来查找具体实现在哪。
这里面要提示一点,使用 //go:linkname,必须导入 unsafe 包,所以,有时候会见到:import _ "unsafe" 这样的代码。
一般来说,我们自己的代码不会使用这样的方式,但你会写一个示例试试吗?欢迎评论给出你的代码。
另外,想想为什么 time.Sleep 的实现要这么搞?
转载自:
为什么 Go 标准库中有些函数只有签名,没有函数体?
为什么 Go 标准库中有些函数只有签名,没有函数体?的更多相关文章
- golang标准库中有些函数只有签名没有函数体是怎么回事?
 - 彻底弄清c标准库中string.h里的常用函数用法
		
在我们平常写的c/c++程序,一些算法题中,我们常常会用到c标准库中string.h文件中的函数,这些函数主要用于处理内存,字符串相关操作,是很有用的工具函数.而且有些时候,在笔试或面试中也会出现让你 ...
 - STL笔记(6)标准库:标准库中的排序算法
		
STL笔记(6)标准库:标准库中的排序算法 标准库:标准库中的排序算法The Standard Librarian: Sorting in the Standard Library Matthew A ...
 - python标准库总的random函数用法
		
Python标准库中的random函数,可以生成随机浮点数.整数.字符串,甚至帮助你随机选择列表序列中的一个元素,打乱一组数据等.random中的一些重要函数的用法:1 ).random() 返回0& ...
 - Python 标准库中的装饰器
		
题目描述 1.简单举例 Python 标准库中的装饰器 2.说说你用过的 Python 标准库中的装饰器 1. 首先,我们比较熟悉,也是比较常用的 Python 标准库提供的装饰器有:property ...
 - c/c++标准库中的文件操作总结
		
1 stdio.h是c标准库中的标准输入输出库 2 在c++中调用的方法 直接调用即可,但是最好在函数名前面加上::,以示区分类的内部函数和c标准库函数. 3 c标准输入输出库的使用 3.1 核心结构 ...
 - C标准库中atoi的一种可能的实现
		
为避免与标准库中的atoi产生歧义, 我将自己编写的函数命名为strToInt, 以下是示例代码 #include <stdio.h> int strToInt(const char *s ...
 - 标准库中的装饰器 lru_cache和全新的 singledispatch
		
Python 内置了三个用于装饰方法的函数:property.classmethod 和 staticmethod. 另一个常见的装饰器是 functools.wraps,它的作用是协助构建行为 良好 ...
 - 用CAS操作实现Go标准库中的Once
		
Go标准库中提供了Sync.Once来实现"只执行一次"的功能.学习了一下源代码,里面用的是经典的双重检查的模式: // Once is an object that will p ...
 
随机推荐
- C语言中表达n次方
			
C语言中表达n次方可以用pow函数. 函数原型:double pow(double x, double y) 功 能:计算x^y的值 返 回 值:计算结果 举例: double a; a = p ...
 - 一款 Postman 的开源替代品: Postwoman
			
1. 前言 大家都知道,Postman是一个非常受欢迎的API接口调试工具,提供有Chrome扩展插件版和独立的APP,不过它的很多高级功能都需要付费才能使用. 如果你连Postman都还没有用过,不 ...
 - IJKPlayerView设置Header播放视频的方法
			
播放b站视频连接的实测图 https://github.com/Rukey7/IjkPlayerView 使用库的连接 在用这个库播放b站视频连接的时候总是播放不了 检查了一下是因为b站视频连接需要验 ...
 - HttpRunner学习4--使用正则表达式提取数据
			
前言 在HttpRunner中,我们可通过extract提取数据,当响应结果为 JSON 结构,可使用 content 结合 . 运算符的方式,如 content.code,用起来十分方便,但如果响应 ...
 - Linux服务器部署.Net Core笔记:六、安装MySQL
			
接下来我们在 Centos7 系统下使用 yum 命令安装 MySQL,需要注意的是 CentOS 7 版本中 MySQL数据库已从默认的程序列表中移除,所以在安装前我们需要先去官网下载 Yum 资源 ...
 - Gradle Java 插件
			
Java 插件是构建 JVM 项目的基础,它为项目增加了很多能力,例如编译,测试,打包,发布等等. 很多插件都是基于 Java 插件实现的,例如 Android 插件. 用法 使用 id 应用插件 p ...
 - python程序员面试高概率会遇到的技术问题
			
本篇只列举会问到的技术问题.其他的问题会在另一篇文章多年职场老狗的面试经验提到. 1. TCP三次握手和四次挥手的过程 2.HTTP协议的状态码 3.讲一下自己用过的设计模式 4.python的多线程 ...
 - go笔记--rpc和grpc使用
			
目录 go笔记--rpc和grpc使用 rpc server.go client.go (sync) client.go (async) grpc protoc server.go client.go ...
 - 如何判断IE OCX插件正常安装?
			
项目中用到了一个第三方的ie ocx控件,而经常遇到客户和测试小伙伴反馈相关功能无法正常使用,也没有友好提示.考虑到这个问题,必须要有一个ie ocx控件的检查机制. 检查原理 创建ActiveXOb ...
 - C#基础之多线程与异步
			
1.基本概念 多线程与异步是两个不同概念,之所以把这两个放在一起学习,是因为这两者虽然有区别,但也有一定联系. 多线程是一个技术概念,相对于单线程而言,多线程是多个单线程同时处理逻辑.例如,假如说一个 ...