一、6 种位运算符及用途
运算符 | 语法 | 功能 | 典型应用场景 |
---|---|---|---|
& |
a & b |
按位与 | 掩码操作、判断奇偶、权限检查 |
` | ` | `a | b` |
^ |
a ^ b |
按位异或 | 交换变量、数据加密、去重 |
&^ |
a &^ b |
位清空(AND NOT) | 清除指定标志位 |
<< |
a << n |
左移 | 快速乘2ⁿ、位掩码生成 |
>> |
a >> n |
右移 | 快速除2ⁿ、提取高位数据 |
💡 关键:
- ^ 作为单目运算符时表示按位取反(如 ^0b1010 = 0b0101)
- &^ 是 Go 特有操作:结果为 a & (^b)
二、4 类实战应用
1. 高效状态管理(权限系统)
go
const (
Read = 1 << iota // 0b001 (1)
Write // 0b010 (2)
Execute // 0b100 (4)
)
// 添加权限:user |= Read | Write
// 检查权限:(user & Read) != 0
// 清除权限:user &^= Write
2. 算法优化(高频题目)
-
判断奇偶:n & 1 == 0 比 n % 2 == 0 快 3~5 倍
-
交换变量(无临时变量):
go
a ^= b
b ^= a
a ^= b
-
2 的幂判断:n & (n-1) == 0
-
只出现一次的数字(LeetCode 136):
go
func singleNumber(nums []int) int {
result := 0
for _, num := range nums {
result ^= num // 利用 a ^ a = 0 的性质
}
return result
}
3. 内存压缩(位图 Bitmap)
go
type Bitmap struct {
bits []uint64
}
// 设置第 n 位为 1
func (b *Bitmap) Set(n int) {
index, offset := n/64, uint(n%64)
b.bits[index] |= 1 << offset
}
// 检查第 n 位
func (b *Bitmap) Get(n int) bool {
index, offset := n/64, uint(n%64)
return (b.bits[index] & (1 << offset)) != 0
}
海量数据去重、快速检索(10亿数据仅需 125MB 内存)
4. 数据编解码
IP 地址转换:
go
ip := 0xC0A80101 // 192.168.1.1
part1 := byte(ip >> 24) // 192
part2 := byte(ip >> 16) // 168
三、避坑指南
1. 运算符优先级问题
❌ 错误写法:
go
if flags & Read != 0 { ... } // 等价于 flags & (Read != 0)
✅ 正确写法:
go
if (flags & Read) != 0 { ... } // 必须加括号!
2. 移位溢出
go
var a uint8 = 255
b := a << 1 // 结果为 254(而非 510),uint8 溢出
移位长度不能超过类型位数(如 int32 最多移 31 位)
3. 负数右移
go
var a int8 = -8 // 二进制: 11111000
b := a >> 2 // 结果: -2 (11111110)
右移负数时高位补 1(符号位扩展)
四、性能优化证据
操作 | 位运算实现 | 传统实现 | 性能提升 |
---|---|---|---|
乘 2 | n << 1 |
n * 2 |
3~5 倍 |
除 2(向下取整) | n >> 1 |
n / 2 |
2~4 倍 |
奇偶判断 | n & 1 |
n % 2 |
4~6 倍 |
取模 2 k 2^k 2k | n & (k-1) |
n % k |
10 倍+ |
⚠️ 注意:现代编译器可能自动优化简单算术,但位运算在复杂表达式和底层系统中仍具优势。
五、灵魂问题
-
Q:x & (x-1) 有什么深层用途?
A:
判断是否为 2 的幂(结果为 0 则是)
计算二进制中 1 的个数(循环直到 0)
求最低位的 1(x & ^(x-1))
-
Q:如何用位运算实现加法?
A:
go
func add(a, b int) int {
for b != 0 {
carry := a & b // 计算进位
a = a ^ b // 无进位加法
b = carry << 1 // 进位左移
}
return a
}
六、真题
题目 :实现函数 func reverseBits(num uint32) uint32(翻转二进制位)
答案:
go
func reverseBits(num uint32) uint32 {
result := uint32(0)
for i := 0; i < 32; i++ {
// 取 num 的最低位,放到 result 的对应高位
result = (result << 1) | (num & 1)
num >>= 1
}
return result
}
💡 注意点:
- 明确位运算优先级(用括号避免歧义)
- 处理负数时说明符号位行为
- 强调位运算在内存敏感场景(嵌入式/高频交易)的价值