Go语言运算符与表达式

运算符用于在表达式中对操作数执行特定的运算。Go语言提供了丰富的运算符,包括算术、关系、逻辑、位运算、赋值、指针运算符等,以及用于运算优先级控制的括号。本章将完整介绍所有运算符的用法,并通过示例展示表达式求值过程。

注意:Go是静态类型语言,运算符两边的操作数类型必须一致(少数例外如无类型常量),否则需要显式类型转换。此外,Go不支持运算符重载。

算术运算符

用于执行基本的数学运算。支持整数和浮点数。

运算符描述示例
+加法a + b
-减法a - b
*乘法a * b
/除法a / b(整数除法结果截断向零)
%取模(仅整数)a % b(结果符号与被除数相同)
算术运算示例
package main

import "fmt"

func main() {
    a, b := 10, 3
    fmt.Println("a + b =", a+b)   // 13
    fmt.Println("a - b =", a-b)   // 7
    fmt.Println("a * b =", a*b)   // 30
    fmt.Println("a / b =", a/b)   // 3(整数除法)
    fmt.Println("a % b =", a%b)   // 1

    // 浮点数除法
    x, y := 10.0, 3.0
    fmt.Println("x / y =", x/y)   // 3.3333333333333335
}

关系运算符

比较两个值,返回布尔值 true 或 false。支持所有基本类型(字符串按字典序比较)。

运算符描述示例
==相等a == b
!=不等a != b
<小于a < b
<=小于等于a <= b
>大于a > b
>=大于等于a >= b
fmt.Println(5 == 5)   // true
fmt.Println(5 != 6)   // true
fmt.Println("go" < "go语言") // true (按字节比较)

逻辑运算符

仅用于布尔值,短路求值。

运算符描述示例
&&逻辑与a && b(若a为false则不计算b)
||逻辑或a || b(若a为true则不计算b)
!逻辑非!a
age := 25
if age > 18 && age < 60 {
    fmt.Println("符合工作年龄")
}

位运算符

直接操作整数的二进制位,支持整型(int, uint等)。

运算符描述示例
&按位与a & b
|按位或a | b
^按位异或(也作一元取反)a ^ b,^a(取反)
&^位清空(AND NOT)a &^ b(将a中b为1的位清零)
<<左移a << n
>>右移a >> n
a := 0b1100  // 12
b := 0b1010  // 10
fmt.Printf("a & b = %b\n", a & b)   // 1000 (8)
fmt.Printf("a | b = %b\n", a | b)   // 1110 (14)
fmt.Printf("a ^ b = %b\n", a ^ b)   // 0110 (6)
fmt.Printf("a &^ b = %b\n", a &^ b) // 0100 (4)
fmt.Printf("a << 2 = %d\n", a << 2) // 48
fmt.Printf("a >> 1 = %d\n", a >> 1) // 6

// 一元取反(对uint类型)
c := uint8(1)      // 00000001
fmt.Printf("^c = %b\n", ^c)       // 11111110 (254)
对有符号整数的右移是算术右移(高位补符号位),对无符号整数是逻辑右移(高位补0)。

赋值运算符

将右侧表达式的值赋给左侧的左值。支持复合赋值。

运算符描述示例
=赋值x = 10
+=加后赋值x += y => x = x + y
-=减后赋值x -= y
*=乘后赋值x *= y
/=除后赋值x /= y
%=取模后赋值x %= y
&=按位与后赋值x &= y
|=按位或后赋值x |= y
^=按位异或后赋值x ^= y
&^=位清空后赋值x &^= y
<<=左移后赋值x <<= 2
>>=右移后赋值x >>= 2

其他运算符

  • & —— 取地址运算符(返回变量的内存地址)。
  • * —— 指针解引用运算符(获取指针指向的值)。
  • <- —— 通道接收/发送运算符(用于并发,后续章节详解)。
x := 100
ptr := &x         // ptr 是 *int 类型
fmt.Println(*ptr) // 解引用,输出 100
*ptr = 200
fmt.Println(x)    // 200

运算符优先级

下表按照优先级从高到低排列。使用括号 () 可以显式改变运算顺序。

优先级运算符结合性
1(最高)* / % << >> & &^左结合
2+ - | ^左结合
3== != < <= > >=左结合
4&&左结合
5(最低)||左结合

一元运算符(如 !、^、*、&)优先级高于乘法类运算符,且是右结合。示例:

// 优先级示例
result := 1 + 2*3   // 7,等同于 1+(2*3)
fmt.Println(8 & 1<<2)  // 0,因为 1<<2 先算,得到4,然后 8 & 4 = 0

复杂表达式示例

综合运算
package main

import "fmt"

func main() {
    a, b, c := 15, 4, 6
    // 算术和关系混合
    result := a+b > c && a-b < c
    fmt.Println(result) // true (19>6 && 11<6? 第二个是false, 故false)
    // 实际执行:左侧 true,右侧 false,&& 结果为 false

    // 位运算
    x, y := 0x0F, 0x33
    z := (x | y) & 0x0F
    fmt.Printf("%#x\n", z) // 0x3

    // 括号改变优先级
    expr := 1 + 2*(3+4)   // 1 + 2*7 = 15
    fmt.Println(expr)
}

自增(++)和自减(--)

Go中的 ++ 和 -- 是语句而不是表达式,不能用于赋值给其他变量,且只能后缀。

count := 0
count++        // 正确,等同于 count += 1
// other = count++  // 编译错误:自增语句不返回值
// ++count          // 编译错误:不支持前缀自增
这种设计避免了C/C++中复杂表达式的副作用,使代码更清晰。

综合示例:温度转换与位运算标志

完整演示
package main

import "fmt"

func main() {
    // 华氏度转摄氏度
    f := 100.0
    c := (f - 32) * 5 / 9
    fmt.Printf("%.1f°F = %.1f°C\n", f, c)

    // 使用位运算设置权限标志
    const (
        Read  = 1 << iota // 1
        Write             // 2
        Exec              // 4
    )
    permissions := Read | Write   // 3 (二进制 011)
    // 检查是否具有Exec权限
    if permissions & Exec == 0 {
        fmt.Println("没有执行权限")
    }
    // 添加Exec权限
    permissions |= Exec
    fmt.Printf("新权限: %#b\n", permissions) // 111 = 7
}
100.0°F = 37.8°C
没有执行权限
新权限: 0b111
小结:运算符是表达式的核心,熟练运用可以编写简洁高效的代码。下一章将学习流程控制,利用运算符构造出分支和循环逻辑。