0

0

惊!Go里面居然有这样精妙的小函数!

Go语言进阶学习

Go语言进阶学习

发布时间:2023-07-24 16:23:58

|

916人浏览过

|

来源于Go语言进阶学习

转载

各位哥麻烦腾个道,前面是大型装逼现场。
惊!Go里面居然有这样精妙的小函数!

首先老许要感谢他人的认同,这是我乐此不彼的动力,同时我也需要反思。这位小姐姐还是比较委婉, 但用我们四川话来说,前一篇文章的标题是真的cuo

老许反复思考后决定哗众取宠一波,感叹号双连取名曰“惊!Go里面居然有这样精妙的小函数!”。下面就让我们来看看和标题没那么符合的一些小函数。

返回a/b向上舍入最接近的整数

func divRoundUp(n, a uintptr) uintptr {
 return (n + a - 1) / a
}

这个方法用过的人应该不少,最典型的就是分页计算。

判断x是否为2的n次幂

func isPowerOfTwo(x uintptr) bool {
 return x&(x-1) == 0
}

这个也挺容易理解的,唯一需要注意的是x需要大于0,因为该等式0也是成立的。

向上/下将x舍入为a的倍数,且a必须是2的n次幂

// 向上将x舍入为a的倍数,例如:x=6,a=4则返回值为8
func alignUp(x, a uintptr) uintptr {
 return (x + a - 1) &^ (a - 1)
}

// 向上将x舍入为a的倍数,例如:x=6,a=4则返回值为4
func alignDown(x, a uintptr) uintptr {
 return x &^ (a - 1)
}

在这里老许再次明确一个概念,2的n次幂即为1左移n位。然后上述代码中^为单目运算法按位取反,则^ (a - 1)的运算结果是除了最低n位为0其余位全为1。剩余的部分则是一个简单的加减运算以及按位与。

上述代码分开来看每一部分都认识,合在一起就一脸懵逼了。幸运的是,经过老许的不懈努力终于找到了一种能够理解的方式。

x=10,a=4为例。a为2的2次幂即1左移2位。x可看作两部分之和,第一部分x1为0b1000,第二部分x2为0b0011x的拆分方式是1左移n位可得到a来决定的,即x的最低n位为x2,x1则为x-x2。因此x1相当于0b10左移2位得到,即x1已经是a的整数倍,此时x2只要大于0则x2+a-1一定会向前进1,x1+1x1不就是x向上舍入的a的整数倍嘛,最后和^ (a - 1)进行与运算将最低2位清零得到最终的返回结果。

有一说一,我肯定是写不出这样的逻辑,这也令我不得不感叹大佬们对计算机的理解简直出神入化。这样的函数牛逼归牛逼,但是在实际开发中还是尽量少用。一是有使用场景的限制(a必须为2的n次幂),二是不易理解,当然炫技和装逼除外(性能要求极高也除外)。

布尔转整形

// bool2int returns 0 if x is false or 1 if x is true.
func bool2int(x bool) int {
 return int(uint8(*(*uint8)(unsafe.Pointer(&x))))
}

如果让我来写这个函数,一个稀松平常的switch就完事儿,现在我又多了一种装逼的套路。老许在这里特别友情提示,字节切片和字符串也可使用上述方式进行相互转换。

计算不同类型最低位0的位数

var ntz8tab = [256]uint8{
 0x08, ..., 0x00,
}
// Ctz8 returns the number of trailing zero bits in x; the result is 8 for x == 0.
func Ctz8(x uint8) int {
 return int(ntz8tab[x])
}

const deBruijn32ctz = 0x04653adf

var deBruijnIdx32ctz = [32]byte{
 0, 1, 2, 6, 3, 11, 7, 16,
 4, 14, 12, 21, 8, 23, 17, 26,
 31, 5, 10, 15, 13, 20, 22, 25,
 30, 9, 19, 24, 29, 18, 28, 27,
}

// Ctz32 counts trailing (low-order) zeroes,
// and if all are zero, then 32.
func Ctz32(x uint32) int {
 x &= -x                       // isolate low-order bit
 y := x * deBruijn32ctz >> 27  // extract part of deBruijn sequence
 i := int(deBruijnIdx32ctz[y]) // convert to bit index
 z := int((x - 1) >> 26 & 32)  // adjustment if zero
 return i + z
}

const deBruijn64ctz = 0x0218a392cd3d5dbf

var deBruijnIdx64ctz = [64]byte{
 0, 1, 2, 7, 3, 13, 8, 19,
 4, 25, 14, 28, 9, 34, 20, 40,
 5, 17, 26, 38, 15, 46, 29, 48,
 10, 31, 35, 54, 21, 50, 41, 57,
 63, 6, 12, 18, 24, 27, 33, 39,
 16, 37, 45, 47, 30, 53, 49, 56,
 62, 11, 23, 32, 36, 44, 52, 55,
 61, 22, 43, 51, 60, 42, 59, 58,
}

// Ctz64 counts trailing (low-order) zeroes,
// and if all are zero, then 64.
func Ctz64(x uint64) int {
 x &= -x                       // isolate low-order bit
 y := x * deBruijn64ctz >> 58  // extract part of deBruijn sequence
 i := int(deBruijnIdx64ctz[y]) // convert to bit index
 z := int((x - 1) >> 57 & 64)  // adjustment if zero
 return i + z
}

Ctz8Ctz32Ctz64分别计算无符号8、32、64位数最低位为0的个数,即某个数左移的位数。

函数的作用通过翻译倒是能理解,我也能深刻的明白这是典型的空间换时间,然而要问一句为什么我是万万答不上来的。不过老许已经替你们找好了答案,原因就藏在这篇Using de Bruijn Sequences to Index a 1 in a Computer Word论文中。欢迎巨佬们去挑战一下,而我只想坐享其成,那么在巨佬们分析完这篇论文之前就让这些函数安家在我的收藏栏里方便以后炫技。

这里特别说明,术业有专攻,我们不一定要所有东西都会,但要尽可能知道有这么一个东西存在。这即是老许为自己找的一个不去研究此论文的接口,也是写下此篇文章的意义之一(万一有人提到了Bruijn Sequences关键词,我们也不至于显得过分无知)。

math/bits包中的部分函数

如果有人知道这个包,那请原谅我的无知直接跳过本部分即可。老许发现这个包是源于ntz8tab变量所在文件runtime/internal/sys/intrinsics_common.go中的一句注释。

// Copied from math/bits to avoid dependence.

作为一个资深的CV工程师, 看到这句的第一反应就是我终于可以挺直腰杆了。适当Copy代码不丢人!

math/bits这个包函数较多,老许挑几个介绍即可,其余的还请各位读者自行挖掘。

LeadingZeros(x uint) int: 返回x所有高位为0的个数。

TrailingZeros(x uint) int: 返回x最低位为0的个数。

OnesCount(x uint) int:返回x中bit位为1的个数。

Reverse(x uint) uint: 将x按bit位倒序后再返回。

Len(x uint) int: 返回表示x的有效bit位个数(高位中的0不计数)。

ReverseBytes(x uint) uint: 将x按照每8位一组倒序后返回。

将x逃逸至堆

// Dummy annotation marking that the value x escapes,
// for use in cases where the reflect code is so clever that
// the compiler cannot follow.
func escapes(x interface{}) {
 if dummy.b {
  dummy.x = x
 }
}

var dummy struct {
 b bool
 x interface{}
}

老许是在reflect.ValueOf函数中发现此函数的调用,当时就觉着挺有意思。如今再次回顾也依旧佩服不已。读书是和作者的对话,阅读源码是和开发者的对话,看到此函数就仿佛看到Go语言开发者们和编译器斗智斗勇的场景。

让出当前Processor

// Gosched yields the processor, allowing other goroutines to run. It does not
// suspend the current goroutine, so execution resumes automatically.
func Gosched() {
 checkTimeouts()
 mcall(gosched_m)
}

让出当前的Processor,允许其他goroutine执行。在实际的开发当中老许还未遇到需要使用此函数的场景,但多了解总是有备无患。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
个人所得税税率表2026 个人所得税率最新税率表
个人所得税税率表2026 个人所得税率最新税率表

以工资薪金所得为例,应纳税额 = 应纳税所得额 × 税率 - 速算扣除数。应纳税所得额 = 月度收入 - 5000 元 - 专项扣除 - 专项附加扣除 - 依法确定的其他扣除。假设某员工月工资 10000 元,专项扣除 1000 元,专项附加扣除 2000 元,当月应纳税所得额为 10000 - 5000 - 1000 - 2000 = 2000 元,对应税率为 3%,速算扣除数为 0,则当月应纳税额为 2000×3% = 60 元。

0

2026.01.26

oppo云服务官网登录入口 oppo云服务登录手机版
oppo云服务官网登录入口 oppo云服务登录手机版

oppo云服务https://cloud.oppo.com/可以在云端安全存储您的照片、视频、联系人、便签等重要数据。当您的手机数据意外丢失或者需要更换手机时,可以随时将这些存储在云端的数据快速恢复到手机中。

1

2026.01.26

抖币充值官方网站 抖币性价比充值链接地址
抖币充值官方网站 抖币性价比充值链接地址

网页端充值步骤:打开浏览器,输入https://www.douyin.com,登录账号;点击右上角头像,选择“钱包”;进入“充值中心”,操作和APP端一致。注意:切勿通过第三方链接、二维码充值,谨防受骗

3

2026.01.26

Java Spring Security 与认证授权
Java Spring Security 与认证授权

本专题系统讲解 Java Spring Security 框架在认证与授权中的应用,涵盖用户身份验证、权限控制、JWT与OAuth2实现、跨站请求伪造(CSRF)防护、会话管理与安全漏洞防范。通过实际项目案例,帮助学习者掌握如何 使用 Spring Security 实现高安全性认证与授权机制,提升 Web 应用的安全性与用户数据保护。

24

2026.01.26

c++ 根号
c++ 根号

本专题整合了c++根号相关教程,阅读专题下面的文章了解更多详细内容。

76

2026.01.23

c++空格相关教程合集
c++空格相关教程合集

本专题整合了c++空格相关教程,阅读专题下面的文章了解更多详细内容。

77

2026.01.23

yy漫画官方登录入口地址合集
yy漫画官方登录入口地址合集

本专题整合了yy漫画入口相关合集,阅读专题下面的文章了解更多详细内容。

301

2026.01.23

漫蛙最新入口地址汇总2026
漫蛙最新入口地址汇总2026

本专题整合了漫蛙最新入口地址大全,阅读专题下面的文章了解更多详细内容。

503

2026.01.23

C++ 高级模板编程与元编程
C++ 高级模板编程与元编程

本专题深入讲解 C++ 中的高级模板编程与元编程技术,涵盖模板特化、SFINAE、模板递归、类型萃取、编译时常量与计算、C++17 的折叠表达式与变长模板参数等。通过多个实际示例,帮助开发者掌握 如何利用 C++ 模板机制编写高效、可扩展的通用代码,并提升代码的灵活性与性能。

17

2026.01.23

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go 教程
Go 教程

共32课时 | 4.2万人学习

Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号