运算符全解
本教程共 80 篇 · 第 16 篇 · 更新于 2026-07-27 · 约 8 分钟阅读
16. 运算符全解
本节目标:掌握 Go 的所有运算符,知道运算符优先级,理解 Go 自增自减的特殊规则。
算术运算符
| 运算符 | 含义 | 示例 |
|---|---|---|
+ | 加 | 3 + 2 = 5 |
- | 减 | 3 - 2 = 1 |
* | 乘 | 3 * 2 = 6 |
/ | 除 | 7 / 2 = 3(整数除法截断) |
% | 取余 | 7 % 3 = 1 |
++ | 自增 | i++ |
-- | 自减 | i-- |
整数除法
Go 的整数除法会直接截断小数部分:
fmt.Println(7 / 2) // 3,不是 3.5
fmt.Println(-7 / 2) // -3,向零截断
要得到浮点结果,至少有一个操作数是浮点数:
fmt.Println(7.0 / 2) // 3.5
fmt.Println(float64(7) / 2) // 3.5
取余
取余的结果符号和被除数一致:
fmt.Println(7 % 3) // 1
fmt.Println(-7 % 3) // -1
fmt.Println(7 % -3) // 1
自增自减的特殊规则
Go 的 ++ 和 -- 是语句,不是表达式。这意味着:
- 只能放在变量后面:
i++ // 正确
++i // 报错
i-- // 正确
--i // 报错
- 没有返回值,不能用在表达式里:
a := i++ // 报错:i++ 不能赋值
b := i-- // 报错
- 只能单独作为一条语句:
i := 0
i++
fmt.Println(i) // 1
NoteGo 把
++和--设计成语句而不是表达式,是为了避免a = b++这种容易出错的写法。简单但安全。
关系运算符
| 运算符 | 含义 | 示例 |
|---|---|---|
== | 等于 | 3 == 3 = true |
!= | 不等于 | 3 != 4 = true |
< | 小于 | 3 < 4 = true |
<= | 小于等于 | 3 <= 3 = true |
> | 大于 | 3 > 4 = false |
>= | 大于等于 | 3 >= 4 = false |
比较结果都是 bool 类型。不同类型之间不能直接比较(需要类型转换)。
fmt.Println(3 == 3) // true
fmt.Println("a" == "a") // true
fmt.Println(3 < 4) // true
逻辑运算符
| 运算符 | 含义 | 示例 |
|---|---|---|
&& | 逻辑与 | true && false = false |
|| | 逻辑或 | true || false = true |
! | 逻辑非 | !true = false |
短路求值
&& 和 || 有短路特性:
&&:如果左边是false,右边不执行||:如果左边是true,右边不执行
func check() bool {
fmt.Println("check 被调用了")
return true
}
func main() {
false && check() // check 不会被调用
true || check() // check 不会被调用
}
这个特性可以用来避免空指针等错误:
if p != nil && p.Value > 0 {
// p 为 nil 时不会访问 p.Value,避免 panic
}
位运算符
| 运算符 | 含义 | 示例 |
|---|---|---|
& | 按位与 | 5 & 3 = 1 |
| | 按位或 | 5 | 3 = 7 |
^ | 按位异或 | 5 ^ 3 = 6 |
&^ | 位清除(AND NOT) | 5 &^ 3 = 4 |
<< | 左移 | 1 << 3 = 8 |
>> | 右移 | 8 >> 2 = 2 |
按位与 &
对应位都为 1,结果才为 1:
fmt.Println(5 & 3) // 1
// 5 = 101
// 3 = 011
// & = 001 = 1
按位或 |
对应位有一个为 1,结果就为 1:
fmt.Println(5 | 3) // 7
// 5 = 101
// 3 = 011
// | = 111 = 7
按位异或 ^
对应位不同为 1,相同为 0:
fmt.Println(5 ^ 3) // 6
// 5 = 101
// 3 = 011
// ^ = 110 = 6
取反 ^
^ 用在单个操作数上时,是按位取反:
fmt.Println(^5) // -6
TipGo 没有
~运算符,取反用的是^。同一个符号在不同上下文有不同含义:两个操作数时是异或,一个操作数时是取反。
位清除 &^
a &^ b 的意思是:把 a 中 b 为 1 的位清零。
fmt.Println(5 &^ 3) // 4
// 5 = 101
// 3 = 011
// 清除第0、1位
// 结果 = 100 = 4
左移 << 和 右移 >>
fmt.Println(1 << 3) // 8,二进制 1000
fmt.Println(8 >> 2) // 2,二进制 10
左移相当于乘 2 的 n 次方,右移相当于除以 2 的 n 次方(向下取整)。
位运算实战:权限标志
const (
Read = 1 << iota // 1 (001)
Write // 2 (010)
Execute // 4 (100)
)
// 组合权限
perm := Read | Write // 3 (011)
// 检查权限
hasRead := perm & Read != 0 // true
hasExec := perm & Execute != 0 // false
// 移除权限
perm = perm &^ Write // 1 (001),移除了写权限
赋值运算符
| 运算符 | 等价写法 |
|---|---|
= | 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 |
>>= | a = a >> b |
&^= | a = a &^ b |
a := 10
a += 5 // a = 15
a -= 3 // a = 12
a *= 2 // a = 24
a /= 5 // a = 4
a <<= 3 // a = 32
其他运算符
| 运算符 | 含义 | 示例 |
|---|---|---|
& | 取地址 | &x |
* | 解引用 | *p |
<- | 接收(channel) | <-ch |
取地址和解引用在指针章节详细讲,channel 操作在并发章节讲。
运算符优先级
Go 的运算符优先级从高到低:
| 优先级 | 运算符 |
|---|---|
| 5 | * / % << >> & &^ |
| 4 | + - | ^ |
| 3 | == != < <= > >= |
| 2 | && |
| 1 | || |
优先级高的先计算。优先级相同时,从左到右计算。
// 乘除优先于加减
fmt.Println(2 + 3 * 4) // 14,不是 20
// 比较优先于逻辑
fmt.Println(1 < 2 && 3 > 2) // true
// 位运算优先级
fmt.Println(1 + 2 << 1) // 5,先算 2<<1=4,再 1+4=5
Tip优先级记不住没关系,用括号。
2 + (3 * 4)比靠优先级判断更清晰,也不会出错。
Go 没有的运算符
和其他语言比,Go 少了一些运算符:
| 运算符 | 说明 |
|---|---|
?:(三元) | Go 没有,用 if-else 替代 |
++i(前置自增) | Go 只有后置 i++ |
--i(前置自减) | Go 只有后置 i-- |
~(取反) | Go 用 ^ 代替 |
没有三元运算符
// 其他语言
// result := condition ? a : b
// Go 的写法
var result int
if condition {
result = a
} else {
result = b
}
虽然啰嗦一些,但更清晰。Go 的设计哲学就是不追求代码极致简短,而追求可读性。
字符串拼接运算符
+ 可以拼接字符串:
s := "Hello" + ", " + "World"
+= 可以追加:
s := "Hello"
s += " World"
Warning字符串拼接会产生新字符串。循环里大量拼接用
strings.Builder,不要用+。
学完这节你能做什么
- 使用所有算术、关系、逻辑、位运算符
- 知道运算符优先级,合理使用括号
- 理解 Go 自增自减的特殊规则
- 用位运算做权限标志
- 知道 Go 有哪些运算符没有,以及替代方案
下一节进入流程控制,从 if-else 开始。