强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Go 语言完全指南 / 05 - 运算符:算术、逻辑、位运算

05 - 运算符

5.1 算术运算符

运算符说明示例结果
+3 + 25
-3 - 21
*3 * 26
/7 / 23(整数除法)
%取模7 % 21
package main

import "fmt"

func main() {
    a, b := 10, 3

    fmt.Println("加:", a+b)   // 13
    fmt.Println("减:", a-b)   // 7
    fmt.Println("乘:", a*b)   // 30
    fmt.Println("除:", a/b)   // 3(整数除法,截断小数)
    fmt.Println("模:", a%b)   // 1

    // 浮点除法
    fa, fb := 10.0, 3.0
    fmt.Println("浮点除:", fa/fb) // 3.3333333333333335

    // 注意:Go 中没有 ++i 和 --i,只有 i++ 和 i--
    i := 10
    i++  // 11
    i--  // 10
    fmt.Println(i)
}

⚠️ 注意

  • Go 的 ++-- 是语句,不是表达式,不能用于赋值:j = i++ 是编译错误
  • 整数除法会截断:-7 / 2 == -3(向零取整)
  • 取模结果的符号与被除数相同:-7 % 2 == -1

5.2 比较运算符

运算符说明示例
==等于3 == 3true
!=不等于3 != 2true
<小于2 < 3true
<=小于等于3 <= 3true
>大于3 > 2true
>=大于等于3 >= 4false
func main() {
    // 数值比较
    fmt.Println(3 == 3)   // true
    fmt.Println(3.0 == 3) // true(不同数值类型可以比较)
    
    // 字符串比较(按字典序)
    fmt.Println("abc" < "abd") // true
    fmt.Println("Go" == "Go")  // true

    // 结构体比较(所有字段可比时)
    type Point struct{ X, Y int }
    p1 := Point{1, 2}
    p2 := Point{1, 2}
    fmt.Println(p1 == p2) // true
}

5.3 逻辑运算符

运算符说明特性
&&逻辑与短路求值:左为 false 则不求右
||逻辑或短路求值:左为 true 则不求右
!逻辑非!truefalse
func main() {
    age := 25
    hasLicense := true

    // && 逻辑与
    canDrive := age >= 18 && hasLicense
    fmt.Println("可以驾驶:", canDrive) // true

    // || 逻辑或
    isStudent := true
    isElderly := false
    canDiscount := isStudent || isElderly
    fmt.Println("可打折:", canDiscount) // true

    // ! 逻辑非
    isWeekend := false
    fmt.Println("是否工作日:", !isWeekend) // true

    // 短路求值
    x := 0
    // 即使 y 未定义也不会执行
    if x != 0 && 10/x > 1 {
        fmt.Println("不会执行")
    }
    fmt.Println("安全的短路")
}

5.4 赋值运算符

运算符说明等价于
=赋值
+=加赋值a = a + b
-=减赋值a = a - b
*=乘赋值a = a * b
/=除赋值a = a / b
%=模赋值a = a % b
&=按位与赋值a = a & b
|=按位或赋值a = a | b
^=按位异或赋值a = a ^ b
<<=左移赋值a = a << b
>>=右移赋值a = a >> b

5.5 位运算符

Go 的位运算符适用于整数类型:

运算符说明示例
&按位与0b1100 & 0b10100b1000
|按位或0b1100 | 0b10100b1110
^按位异或0b1100 ^ 0b10100b0110
&^位清除(AND NOT)0b1100 &^ 0b10100b0100
<<左移1 << 38
>>右移8 >> 22
package main

import "fmt"

func main() {
    a := 0b11001010 // 202
    b := 0b10101100 // 172

    fmt.Printf("a:      %08b (%d)\n", a, a)
    fmt.Printf("b:      %08b (%d)\n", b, b)
    fmt.Printf("a & b:  %08b (%d)\n", a&b, a&b)     // AND
    fmt.Printf("a | b:  %08b (%d)\n", a|b, a|b)     // OR
    fmt.Printf("a ^ b:  %08b (%d)\n", a^b, a^b)     // XOR
    fmt.Printf("a &^ b: %08b (%d)\n", a&^b, a&^b)   // AND NOT (清除)
    fmt.Printf("a << 2: %08b (%d)\n", a<<2, a<<2)   // 左移
    fmt.Printf("a >> 2: %08b (%d)\n", a>>2, a>>2)   // 右移

    // 取反(Go 没有 ~ 运算符,用 ^)
    fmt.Printf("^a:     %08b (%d)\n", ^a, ^a)
}

位运算实际应用

package main

import "fmt"

// 权限系统
const (
    PermRead    = 1 << iota // 001 = 1
    PermWrite               // 010 = 2
    PermExecute             // 100 = 4
)

func main() {
    // 设置权限
    var perm uint8
    perm |= PermRead    // 添加读权限
    perm |= PermWrite   // 添加写权限
    fmt.Printf("权限: %03b\n", perm) // 011

    // 检查权限
    if perm&PermRead != 0 {
        fmt.Println("有读权限")
    }
    if perm&PermExecute != 0 {
        fmt.Println("有执行权限")
    } else {
        fmt.Println("无执行权限")
    }

    // 清除权限
    perm &^= PermWrite  // 移除写权限
    fmt.Printf("移除写权限后: %03b\n", perm) // 001

    // 切换权限
    perm ^= PermExecute // 切换执行权限
    fmt.Printf("切换执行权限后: %03b\n", perm) // 101

    // 实际案例:判断奇偶
    for i := 0; i < 5; i++ {
        if i&1 == 0 {
            fmt.Printf("%d 是偶数\n", i)
        } else {
            fmt.Printf("%d 是奇数\n", i)
        }
    }

    // 快速乘除 2 的幂
    x := 10
    fmt.Printf("%d << 1 = %d (×2)\n", x, x<<1)  // 20
    fmt.Printf("%d << 3 = %d (×8)\n", x, x<<3)  // 80
    fmt.Printf("%d >> 1 = %d (÷2)\n", x, x>>1)  // 5
}

5.6 运算符优先级

Go 的运算符优先级(从高到低):

优先级运算符
5*, /, %, <<, >>, &, &^
4+, -, |, ^
3==, !=, <, <=, >, >=
2&&
1||

💡 技巧:不确定优先级时使用括号 () 明确意图。

func main() {
    a, b, c := 1, 2, 3

    // 不明确
    result1 := a + b*c     // 7 (先乘后加)
    result2 := (a + b) * c // 9 (先加后乘)
    fmt.Println(result1, result2)

    // 位运算优先级高于比较运算
    x := 5
    fmt.Println(x&1 == 1)  // 等价于 (x&1) == 1,正确
}

5.7 类型相关的运算限制

func main() {
    // 不同类型的数值不能直接运算
    var i int = 10
    var f float64 = 3.14
    // result := i + f // 编译错误
    result := float64(i) + f // 需要显式转换
    fmt.Println(result)

    // 不同大小的整数不能直接运算
    var a int32 = 10
    var b int64 = 20
    // c := a + b // 编译错误
    c := int64(a) + b
    fmt.Println(c)

    // 指针运算不是直接支持的
    arr := [3]int{10, 20, 30}
    p := &arr[0]
    // p++ // 编译错误:Go 不支持指针运算
    fmt.Println(*p)
}

🏢 业务场景

  1. 权限管理:用位运算组合和检查权限标志
  2. IP 地址处理:位运算计算子网掩码、网络地址
  3. 状态标志:用位掩码管理多个布尔状态
  4. 数据压缩:位运算实现紧凑的数据编码
  5. 哈希计算:使用 ^<< 实现简单哈希

📖 扩展阅读