位运算符 #
一、运算符概述 #
Go语言支持以下位运算符:
| 运算符 | 说明 | 示例 |
|---|---|---|
| & | 按位与 | a & b |
| | | 按位或 | a | b |
| ^ | 按位异或 | a ^ b |
| &^ | 按位清除 | a &^ b |
| << | 左移 | a << n |
| >> | 右移 | a >> n |
位运算符操作整数的二进制位。
二、按位与 (&) #
2.1 基本用法 #
对应位都为1时结果为1:
go
a := 12 // 1100
b := 10 // 1010
fmt.Println(a & b) // 8 (1000)
2.2 真值表 #
| A | B | A & B |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
2.3 实际应用 #
判断奇偶:
go
n := 7
if n&1 == 1 {
fmt.Println("奇数")
} else {
fmt.Println("偶数")
}
取特定位:
go
n := 0b11010110
lower4 := n & 0b1111 // 取低4位
fmt.Printf("%b\n", lower4) // 110
三、按位或 (|) #
3.1 基本用法 #
对应位任一为1时结果为1:
go
a := 12 // 1100
b := 10 // 1010
fmt.Println(a | b) // 14 (1110)
3.2 真值表 #
| A | B | A | B |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 1 |
3.3 实际应用 #
设置标志位:
go
const (
Read = 1 << iota // 1
Write // 2
Execute // 4
)
perm := Read | Write // 3
fmt.Printf("%b\n", perm) // 11
四、按位异或 (^) #
4.1 基本用法 #
对应位不同时结果为1:
go
a := 12 // 1100
b := 10 // 1010
fmt.Println(a ^ b) // 6 (0110)
4.2 真值表 #
| A | B | A ^ B |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
4.3 一元运算 #
作为一元运算符时,表示按位取反:
go
a := 5
fmt.Println(^a) // -6(补码表示)
4.4 实际应用 #
交换两个数:
go
a, b := 10, 20
a = a ^ b
b = a ^ b
a = a ^ b
fmt.Println(a, b) // 20 10
简单加密:
go
key := 0x55
data := 0xAA
encrypted := data ^ key // 加密
decrypted := encrypted ^ key // 解密
fmt.Println(decrypted == data) // true
五、按位清除 (&^) #
5.1 基本用法 #
将第二个操作数为1的位清零:
go
a := 12 // 1100
b := 10 // 1010
fmt.Println(a &^ b) // 4 (0100)
5.2 等价表达式 #
a &^ b 等价于 a & (^b)
5.3 实际应用 #
清除标志位:
go
const (
Read = 1 << iota // 1
Write // 2
Execute // 4
)
perm := Read | Write | Execute // 7
perm = perm &^ Write // 清除Write标志
fmt.Printf("%b\n", perm) // 101
六、左移 (<<) #
6.1 基本用法 #
所有位向左移动,低位补0:
go
a := 5 // 101
fmt.Println(a << 1) // 10 (1010)
fmt.Println(a << 2) // 20 (10100)
6.2 数学意义 #
左移n位相当于乘以2^n:
go
a := 3
fmt.Println(a << 3) // 24 (3 * 2^3)
6.3 实际应用 #
快速乘法:
go
n := 10
fmt.Println(n << 1) // 20 (乘以2)
fmt.Println(n << 2) // 40 (乘以4)
七、右移 (>>) #
7.1 基本用法 #
所有位向右移动:
go
a := 20 // 10100
fmt.Println(a >> 1) // 10 (1010)
fmt.Println(a >> 2) // 5 (101)
7.2 算术右移 #
对于有符号数,右移时高位补符号位:
go
a := -8 // 负数
fmt.Println(a >> 1) // -4
7.3 数学意义 #
右移n位相当于除以2^n(向下取整):
go
a := 20
fmt.Println(a >> 2) // 5 (20 / 2^2)
7.4 实际应用 #
快速除法:
go
n := 100
fmt.Println(n >> 1) // 50 (除以2)
fmt.Println(n >> 2) // 25 (除以4)
八、实际应用示例 #
8.1 权限系统 #
go
const (
PermissionRead = 1 << iota // 1
PermissionWrite // 2
PermissionDelete // 4
PermissionAdmin // 8
)
type User struct {
Permissions int
}
func (u *User) HasPermission(perm int) bool {
return u.Permissions&perm != 0
}
func (u *User) Grant(perm int) {
u.Permissions |= perm
}
func (u *User) Revoke(perm int) {
u.Permissions &^= perm
}
func main() {
user := &User{}
user.Grant(PermissionRead | PermissionWrite)
fmt.Println(user.HasPermission(PermissionRead)) // true
fmt.Println(user.HasPermission(PermissionDelete)) // false
}
8.2 颜色处理 #
go
func rgb(r, g, b uint8) uint32 {
return uint32(r)<<16 | uint32(g)<<8 | uint32(b)
}
color := rgb(255, 128, 0)
r := uint8(color >> 16)
g := uint8((color >> 8) & 0xFF)
b := uint8(color & 0xFF)
fmt.Printf("R:%d G:%d B:%d\n", r, g, b)
8.3 判断2的幂 #
go
func isPowerOfTwo(n int) bool {
return n > 0 && n&(n-1) == 0
}
fmt.Println(isPowerOfTwo(8)) // true
fmt.Println(isPowerOfTwo(10)) // false
8.4 统计1的个数 #
go
func countBits(n int) int {
count := 0
for n != 0 {
count += n & 1
n >>= 1
}
return count
}
fmt.Println(countBits(7)) // 3 (111)
fmt.Println(countBits(10)) // 2 (1010)
九、常见错误 #
9.1 溢出 #
go
var a uint8 = 255
fmt.Println(a << 1) // 254(溢出回绕)
9.2 移位数为负数 #
go
a := 1
fmt.Println(a << -1) // 编译错误或运行时错误
9.3 类型不匹配 #
go
var a int8 = 10
var b int16 = 5
fmt.Println(a & b) // 错误:类型不匹配
十、总结 #
位运算符要点:
| 运算符 | 说明 | 示例 |
|---|---|---|
| & | 按位与 | 12 & 10 = 8 |
| | | 按位或 | 12 | 10 = 14 |
| ^ | 按位异或 | 12 ^ 10 = 6 |
| &^ | 按位清除 | 12 &^ 10 = 4 |
| << | 左移 | 5 << 2 = 20 |
| >> | 右移 | 20 >> 2 = 5 |
关键点:
- 操作整数:只能用于整数类型
- 二进制操作:直接操作二进制位
- 高效:位运算通常比算术运算更快
- 应用场景:权限系统、颜色处理、算法优化
准备好学习赋值运算符了吗?让我们进入下一章!
最后更新:2026-03-26