2.3 运算符
本节目标:熟悉算术、比较、逻辑、赋值运算符;重点记住 Go 和其他语言不一样的几处设计。
变量存好了数据,这一节让数据"动"起来——算、比、判断。Go 的运算符大部分和你直觉一致,真正要花心思的是它刻意"砍掉"的那些东西,我们把重点放在差异上。
一、算术运算符
fmt.Println(5 + 2) // 7
fmt.Println(5 - 2) // 3
fmt.Println(5 * 2) // 10
fmt.Println(5 / 2) // 2 ← 上一节的老朋友:整数除法截断
fmt.Println(5 % 2) // 1 ← 取余
两个补充点:
fmt.Println(5.0 / 2) // 2.5(有浮点数参与才是浮点除法)
fmt.Println(-5 % 2) // -1(余数的符号跟随被除数,Python 转来的注意:Python 里是 1)
/ 和 % 配合是拆数字的万能钳。比如把 3725 秒拆成时分秒:
total := 3725
hours := total / 3600 // 1 整除得"商"
minutes := total % 3600 / 60 // 2 取余得"剩下的",再拆
seconds := total % 60 // 5
自增自减:i++ 是语句,不是表达式
Go 有 ++ 和 --,但和 C/Java/JS 的规则大不一样:
i := 0
i++ // ✅ i 变成 1
i-- // ✅ i 变回 0
x := i++ // ❌ syntax error: unexpected ++
++i // ❌ syntax error: unexpected ++(没有前缀写法)
规则一句话:++/-- 只能单独占一行,不能嵌在任何表达式里。这是 Go 刻意的简化——C 语言里 a[i++] = ++i 这种"考试题代码"在 Go 里根本写不出来。
二、比较运算符
==、!=、>、<、>=、<=,结果都是 bool:
fmt.Println(3 == 3) // true
fmt.Println(3 != 5) // true
fmt.Println("abc" == "abc") // true —— 字符串能直接 == 比较(Java 转来的泪目)
fmt.Println("a" < "b") // true(按字典序)
两个注意点:
- 判等是两个等号
==,一个=是赋值。好消息:Go 里if x = 5 {}直接编译报错,不会像 C 那样埋雷。 - 只有相同类型才能比较。int 变量和 float64 变量连
==都不让比,先转换——静态类型的严格贯彻到底:
var a int = 3
var b float64 = 3.0
fmt.Println(a == b) // ❌ mismatched types
fmt.Println(float64(a) == b) // ✅ true
三、逻辑运算符
把多个条件拼起来。注意 Go 用的是符号,不是 Python 的 and/or/not:
| 运算符 | 含义 | 示例 |
|---|---|---|
&& | 与(都要满足) | age > 0 && age < 120 |
|| | 或(满足一个就行) | day == 6 || day == 7 |
! | 非(取反) | !isDone |
age := 20
hasTicket := true
if age >= 18 && hasTicket {
fmt.Println("可以入场")
}
⚠️ 高频坑:条件写一半。"年龄在 18 到 60 之间"不能写成数学课的样子:
if 18 <= age <= 60 {} // ❌ 编译报错:18 <= age 的结果是 bool,bool 没法再和 60 比if age >= 18 && age <= 60 {} // ✅ 每个条件都要写完整
短路求值:不只是省事,是安全机制
&& 左边为 false 时,右边根本不会执行;|| 左边为 true 时同理。这不是冷知识,是天天要用的防崩溃技巧:
// 若 len(s) > 0 为 false,s[0] 不会执行 —— 避免空字符串越界崩溃
if len(s) > 0 && s[0] == 'A' {
// ...
}
把"保命条件"写在左边,"可能出事的操作"写在右边——这个顺序习惯以后判断 nil、判断 map 里有没有键时都靠它。
四、赋值运算符
x = x + 5 这种"自己更新自己"的写法太常用,Go 提供了缩写:
x := 10
x += 5 // x = x + 5 → 15
x -= 3 // 12
x *= 2 // 24
x /= 4 // 6
x %= 4 // 2
读法还是 2.1 教的:先算右边,再存回左边。x += 5 就是"x 增加 5"。
五、位运算符(认识即可)
直接操作二进制位,新手阶段几乎用不到,认得出来就行:
| 运算符 | 含义 |
|---|---|
& | 按位与 |
| | 按位或 |
^ | 按位异或 |
<< >> | 左移 / 右移 |
fmt.Println(1 << 3) // 8(1 左移 3 位 = 乘 2³)
唯一提醒:
^不是幂运算!2 ^ 10不报错但得到的是 8(异或结果)——典型的"不报错的错"。幂运算见下表。
六、Go 没有的运算符(其他语言转来的必看)
Go 的设计哲学是"一件事只有一种写法",砍掉了不少别的语言的糖:
| 其他语言有 | Go 的替代方案 |
|---|---|
三元运算符 a ? b : c | 没有,老老实实写 if/else |
** 或 ^(幂运算) | math.Pow(2, 10)(返回 float64) |
前缀 ++i | 只有后缀 i++,且只能单独成行 |
Python 的 and / or / not | && / || / ! |
// 想写 max = a > b ? a : b?Go 里只能:
max := a
if b > a {
max = b
}
看着啰嗦,但读代码的人一眼就懂——Go 宁可多写三行,也不要一行看三遍。
七、运算优先级
大致规律:! > 乘除取余 > 加减 > 比较 > && > ||。
但真正的最佳实践是:记不住就加括号。
result := (a + b) * c / (d - e) // 谁看都不会错
本节报错/怪象速查表
| 现象 | 人话翻译 |
|---|---|
syntax error: unexpected ++ | ++ 被写进了表达式(x := i++)或写成前缀(++i),只能单独一行 |
mismatched types int and float64 | 不同类型不能比较/运算,先转换 |
invalid operation: 18 <= age <= 60 | 条件要写完整:age >= 18 && age <= 60 |
cannot use x = 5 as value | if 条件里把 == 写成了 = |
2 ^ 10 得 8(不报错) | ^ 是异或不是幂,幂用 math.Pow |
练习
1. 动手:写程序判断变量 year 是否是闰年(能被 4 整除但不能被 100 整除,或能被 400 整除),打印 true/false。
2. 动手:已知 total := 3725 秒,用 / 和 % 算出它等于几小时几分钟几秒。
3. 猜输出:先别运行,猜猜每行打印什么?
a := 7
a += 3
a /= 2
fmt.Println(a)
fmt.Println(a % 3)
fmt.Println(a > 3 && a < 10)
4. 修 bug:下面的代码想判断成绩是否在及格区间(60~100),有 2 处编译错误:
func main() {
score := 75
if 60 <= score <= 100 {
fmt.Println("及格")
}
score++
bonus := score++
fmt.Println(bonus)
}
点击查看答案
// 1
year := 2024
isLeap := (year%4 == 0 && year%100 != 0) || year%400 == 0
fmt.Println(isLeap) // true
// 2
total := 3725
fmt.Printf("%d 小时 %d 分 %d 秒\n", total/3600, total%3600/60, total%60)
// 1 小时 2 分 5 秒
3. 输出:
5 ← a = 7+3 = 10,再 10/2 = 5
2 ← 5 % 3
true ← 5 在 (3, 10) 区间内
4. 两处错误:
func main() {
score := 75
if score >= 60 && score <= 100 { // ① 条件必须写完整,不能连着比
fmt.Println("及格")
}
score++
score++ // ② ++ 不能出现在赋值右边,只能单独成行
bonus := score
fmt.Println(bonus) // 77
}
本节小结
- 算术运算符照常用,牢记整数除法截断;
/+%是拆数字的组合拳 ++/--只能单独成行,不能嵌进表达式- 字符串能直接
==比较;不同类型比较要先转换 - 逻辑运算用
&&||!;区间条件写完整;短路求值是防崩溃机制 - Go 没有三元运算符、没有幂运算符(
^是异或!),if/else 和math.Pow伺候 - 优先级记不住就加括号
下一节:2.4 流程控制