Go 语言位运算符全面总结
📊 位运算符速查表
| 运算符 |
名称 |
示例 |
结果 |
记忆技巧 |
& |
位与 (AND) |
1010 & 1100 |
1000 |
都为1才是1 |
| |
位或 (OR) |
1010 | 1100 |
1110 |
有1就是1 |
^ |
位异或 (XOR) |
1010 ^ 1100 |
0110 |
不同为1 |
&^ |
位清除 (AND NOT) |
1010 &^ 1100 |
0010 |
清除右边为1的位 |
<< |
左移 |
0011 << 2 |
1100 |
乘以2^n |
>> |
右移 |
1100 >> 2 |
0011 |
除以2^n |
^(一元) |
位取反 (NOT) |
^1010 |
...0101 |
0变1,1变0 |
🔍 详细功能解析
1. 位与 & - 按位与
// 功能:两个位都为1时结果为1,否则为0
func bitwiseAND() {
a := 0b1010 // 10
b := 0b1100 // 12
result := a & b // 0b1000 = 8
fmt.Printf("%04b & %04b = %04b\n", a, b, result)
// 输出: 1010 & 1100 = 1000
// 应用场景:
// 1. 检查特定位是否为1
flags := 0b1101
mask := 0b0100 // 检查第2位
if flags & mask != 0 {
fmt.Println("第2位是1")
}
// 2. 清除某些位(通过与0相与)
clearMask := ^0b0010 // 1110...1101
cleared := flags & clearMask // 清除第1位
}
2. 位或 | - 按位或
// 功能:两个位有1个为1时结果为1
func bitwiseOR() {
a := 0b1010 // 10
b := 0b1100 // 12
result := a | b // 0b1110 = 14
fmt.Printf("%04b | %04b = %04b\n", a, b, result)
// 输出: 1010 | 1100 = 1110
// 应用场景:
// 1. 设置特定位为1
flags := 0b0000
setMask := 0b0010
flags = flags | setMask // 设置第1位为1
// 2. 组合多个标志
read := 1 << 0 // 0001
write := 1 << 1 // 0010
exec := 1 << 2 // 0100
permissions := read | write | exec // 0111
}
3. 位异或 ^ - 按位异或
// 功能:两个位不同时结果为1,相同时为0
func bitwiseXOR() {
a := 0b1010 // 10
b := 0b1100 // 12
result := a ^ b // 0b0110 = 6
fmt.Printf("%04b ^ %04b = %04b\n", a, b, result)
// 输出: 1010 ^ 1100 = 0110
// 应用场景:
// 1. 切换位(0变1,1变0)
flags := 0b1010
toggleMask := 0b0011
toggled := flags ^ toggleMask // 1001
// 2. 交换两个数(不用临时变量)
x, y := 5, 9
x = x ^ y
y = x ^ y
x = x ^ y
// 现在 x=9, y=5
// 3. 加密/解密(相同密钥两次异或得到原值)
data := 42
key := 123
encrypted := data ^ key
decrypted := encrypted ^ key // 变回42
}
4. 位清除 &^ - AND NOT(Go特有)
// 功能:清除a中在b里为1的位
func bitwiseAndNot() {
a := 0b1010 // 10
b := 0b1100 // 12
result := a &^ b // 0b0010 = 2
fmt.Printf("%04b &^ %04b = %04b\n", a, b, result)
// 输出: 1010 &^ 1100 = 0010
// 等价于:a & (^b)
// 但比 ^ 优先级高,更安全
// 应用场景:
// 1. 清除特定标志位
flags := 0b1111
clearMask := 0b1010
cleared := flags &^ clearMask // 0101
// 2. 从集合中移除元素(差集)
setA := 0b1101 // 元素 {0, 2, 3}
setB := 0b0110 // 元素 {1, 2}
diff := setA &^ setB // 1101,移除交集
}
5. 左移 << - 向左移位
// 功能:所有位向左移动,右侧补0
func leftShift() {
x := 0b0001 // 1
result := x << 3 // 0b1000 = 8
fmt.Printf("%04b << 3 = %04b (%d)\n", x, result, result)
// 输出: 0001 << 3 = 1000 (8)
// 应用场景:
// 1. 快速乘以2的幂
n := 5
doubled := n << 1 // 10
times8 := n << 3 // 40
// 2. 创建位掩码
bit3 := 1 << 3 // 00001000
bits2and3 := (1<<2) | (1<<3) // 00001100
// 3. 标志位定义
const (
FlagA = 1 << iota // 1
FlagB // 2
FlagC // 4
FlagD // 8
)
}
6. 右移 >> - 向右移位
// 功能:所有位向右移动
func rightShift() {
x := 0b1000 // 8
result := x >> 2 // 0b0010 = 2
fmt.Printf("%04b >> 2 = %04b (%d)\n", x, result, result)
// 输出: 1000 >> 2 = 0010 (2)
// 注意:有符号数和无符号数右移行为不同!
// 无符号数:左侧补0
// 有符号数:左侧补符号位(算术右移)
var u uint8 = 0b10000000 // 128
var s int8 = -128 // 二进制也是10000000
fmt.Printf("无符号: %08b >> 1 = %08b (%d)\n", u, u>>1, u>>1)
fmt.Printf("有符号: %08b >> 1 = %08b (%d)\n", byte(s), s>>1, s>>1)
// 应用场景:
// 1. 快速除以2的幂(无符号数)
n := 16
half := n >> 1 // 8
// 2. 提取特定位
value := 0b11010110
bit3 := (value >> 3) & 1 // 提取第3位
// 3. 分解字节
rgb := 0xFF3366
r := (rgb >> 16) & 0xFF // 红色分量
g := (rgb >> 8) & 0xFF // 绿色分量
b := rgb & 0xFF // 蓝色分量
}
7. 位取反 ^ - 一元运算符
// 功能:所有位取反(0变1,1变0)
func bitwiseNOT() {
x := uint8(0b00001111) // 15
result := ^x // 0b11110000 = 240
fmt.Printf("^%08b = %08b\n", x, result)
// 输出: ^00001111 = 11110000
// 注意:Go中^既是一元也是二元运算符
// 一元:位取反
// 二元:异或
// 应用场景:
// 1. 创建掩码的反码
mask := 0b00001111
invertedMask := ^mask // 11110000
// 2. 求补码(有符号数)
// Go中整数以补码形式存储
// 3. 清除特定位(与&^配合)
flags := 0b1111
keepMask := 0b1100 // 保留高2位
cleared := flags & ^keepMask // 清除低2位
}
📊 组合使用示例
示例1:权限系统
// 使用位运算实现权限控制
const (
Read = 1 << iota // 0001
Write // 0010
Execute // 0100
Delete // 1000
)
type User struct {
permissions byte
}
func (u *User) addPermission(perm byte) {
u.permissions |= perm // 设置位
}
func (u *User) removePermission(perm byte) {
u.permissions &^= perm // 清除位
}
func (u *User) hasPermission(perm byte) bool {
return u.permissions & perm != 0 // 检查位
}
func (u *User) togglePermission(perm byte) {
u.permissions ^= perm // 切换位
}
示例2:位标志操作
func bitFlagOperations() {
// 初始化标志
var flags uint8 = 0
// 设置标志
flags |= 0b00000001 // 设置第0位
flags |= 0b00000100 // 设置第2位
fmt.Printf("设置后: %08b\n", flags) // 00000101
// 检查标志
if flags & 0b00000100 != 0 {
fmt.Println("第2位已设置")
}
// 清除标志
flags &^= 0b00000001 // 清除第0位
fmt.Printf("清除后: %08b\n", flags) // 00000100
// 切换标志
flags ^= 0b00001000 // 切换第3位
fmt.Printf("切换后: %08b\n", flags) // 00001100
// 获取所有设置的位
for i := 0; i < 8; i++ {
if flags & (1 << i) != 0 {
fmt.Printf("位 %d 已设置\n", i)
}
}
}
示例3:颜色操作(RGBA)
func colorOperations() {
// 32位ARGB颜色:A R G B 各8位
color := uint32(0xFF336699) // Alpha=FF, R=33, G=66, B=99
// 提取各分量
alpha := (color >> 24) & 0xFF
red := (color >> 16) & 0xFF
green := (color >> 8) & 0xFF
blue := color & 0xFF
fmt.Printf("A=%02X R=%02X G=%02X B=%02X\n", alpha, red, green, blue)
// 修改分量
// 将红色分量改为0xAA
color = (color & 0xFF00FFFF) | (0xAA << 16)
// 降低亮度(所有分量减半)
color = ((color >> 1) & 0x7F7F7F7F) | (alpha << 24)
// 创建新颜色
newColor := (0xFF << 24) | (0x12 << 16) | (0x34 << 8) | 0x56
}
🎯 优先级和结合性
| 优先级 |
运算符 |
说明 |
| 1 |
^(一元) |
位取反 |
| 2 |
<< >> |
移位 |
| 3 |
& |
位与 |
| 4 |
^(二元) |
位异或 |
| 5 |
| |
位或 |
| 6 |
&^ |
位清除 |
使用括号明确优先级:
// 容易混淆的表达式
result1 := a & b ^ c // (a & b) ^ c
result2 := a & (b ^ c) // 不同的结果!
// 总是使用括号使意图明确
clear := (a & ^b) // 与 a &^ b 相同
💡 实用技巧
1. 判断奇偶性
func isEven(n int) bool {
return n & 1 == 0 // 比 n%2 == 0 更快
}
2. 交换两个变量
func swap(a, b int) (int, int) {
a ^= b
b ^= a
a ^= b
return a, b // 不用临时变量
}
3. 判断是否是2的幂
func isPowerOfTwo(n int) bool {
return n > 0 && (n & (n-1)) == 0
}
4. 获取最低位的1
func lowestSetBit(n int) int {
return n & -n // 如:1010 & 0110 = 0010
}
5. 统计1的个数(Brian Kernighan算法)
func countOnes(n uint) int {
count := 0
for n != 0 {
n &= n - 1 // 清除最低位的1
count++
}
return count
}