跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

Go语言怎么做位图_Go语言BitMap位图教程【全面】

Go中用[]uint64+位运算实现位图,每单元存64位;索引计算为byteIndex=index>>6、bitOffset=index&63;设置位用bits[byteIndex] |= 1<bit
操作实现位图(BitMap) Go 没有内置 BitMap 类型,但靠
[]uint64
+ 位运算就能高效实现。核心是把每个 bit 当作一个布尔开关,用整数数组存状态,省空间、快访问。 常见错误是直接用
[]bool
—— 它每个元素占 1 字节,浪费 8 倍内存;或者手写位移时搞错索引:比如把
index / 64
写成
index >> 6
却忘了加括号,导致优先级出错。 用
[]uint64
存储,每 64 个 bit 打包进一个单元 位位置计算必须用:
byteIndex := index / 64
和
bitOffset := index % 64
(或等价的
index >> 6
和
index & 63
) 设置 bit:
bits[byteIndex] |= 1
读取 bit:
(bits[byteIndex] & (1
为什么不用
math/bits
的
OnesCount64
就算不了位图?
math/bits.OnesCount64
只统计某一个
uint64
里有几个 1,它不操作位图本身,只是辅助函数。位图的核心是随机读写任意位置的 bit,不是数 1 的个数。 误用场景:想查“第 1000 位是否为 1”,却去调
OnesCount64(bits[15])
—— 这只能告诉你第 960~1023 位里总共几个 1,没法定位到第 1000 位。 立即学习 “ go语言免费学习笔记(深入) ”; go语言参考手册 中文CHM版 Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。本文给大家带来Go参考手册,需要的可以来下载! Go是从2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。现在Go的开发已经是完全开放的,并且拥有一个活跃的社区。 Go 语言特色 简洁、快速、安全 并行、有趣、开源 内存管理、v数组安全、编译 下载 真要用
math/bits
,推荐
bits.LeadingZeros64
或
bits.TrailingZeros64
做稀疏位图的快速跳转 批量 set/clear 某段连续 bit 时,建议按
uint64
对齐操作,避免单 bit 循环,性能差 10 倍以上 注意小端序不影响位图逻辑——Go 的位运算是平台无关的,
1 永远是最低位
并发写
BitMap
时为什么 panic 或结果错? 多个 goroutine 直接读写同一个
[]uint64
元素会触发 data race,Go runtime 可能 panic,也可能静默出错(比如两个 goroutine 同时 set 第 123 位,最终只生效一次)。 不是所有场景都要加锁:如果写操作是“只增不删”且可容忍少量重复(如布隆过滤器),可用
sync/atomic
的
OrUint64
;否则必须保护整个数组或分段加锁。 最简方案:用
sync.Mutex
包一层
Set
/
Get
方法 高并发场景:按
uint64
索引分段加锁,例如每 8 个
uint64
共用一个
*sync.RWMutex
千万别用
atomic.LoadUint64
读单个
uint64
就以为线程安全——set 操作可能只改其中几位,非原子写会导致撕裂 用
github.com/zeebo/bloom
或
golang.org/x/exp/slices
能替代手写位图吗? 不能直接替代。前者是布隆过滤器封装,底层虽用位图但接口固定(只支持 add/test,不支持随机 get/set);后者压根没有位图相关功能——
slices
是泛型切片工具集,和 bit 无关。 真正需要自定义行为时(比如带版本号的位图、持久化到 mmap 文件、支持 range 查询),还是得自己管内存布局和位运算逻辑。 如果只是去重+存在性判断,用
zeebo/bloom
更省心 如果要支持
Count()
、
NextSet(1000)
(找下一个为 1 的位置)、或和 protobuf 二进制互转,手写控制权更大 注意:
unsafe.Slice
在 Go 1.21+ 可用于零拷贝构造大位图,但需确保底层数组对齐到 8 字节,否则
uint64
读写会 panic 事情说清了就结束

相关文章