位运算符 #

一、运算符概述 #

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

关键点:

  1. 操作整数:只能用于整数类型
  2. 二进制操作:直接操作二进制位
  3. 高效:位运算通常比算术运算更快
  4. 应用场景:权限系统、颜色处理、算法优化

准备好学习赋值运算符了吗?让我们进入下一章!

最后更新:2026-03-26