一次性带你彻底学透 Golang 操作运算符
Golang 运算符分类总览
Golang 运算符按功能可分为 5 大类:算术运算符、赋值运算符、比较运算符、逻辑运算符、位运算符。
不同类型的运算符有明确的使用场景和优先级。
提示:Golang 没有三元运算符(如 a?b:c),这是和其他语言的明显区别。
算术运算符
处理数值计算的核心
算术运算符用于整数、浮点数的加减乘除等计算,共 7 个,其中取模(%)和自增自减(++、–)。
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
// 除法注意:Golang 中整数相除结果取整,浮点数相除才保留小数
fmt.Println("a / b =", a / b) // 输出 3(不是 3.333)
fmt.Println("a / float64(b) =", float64(a) / float64(b)) // 输出 3.333...
// 取模运算:结果符号与被除数一致
fmt.Println("a % b =", a % b) // 输出 1(10 = 3*3 +1)
fmt.Println("-a % b =", -a % b) // 输出 -1(符号随被除数 -10)
// 自增自减:只能独立使用,不能参与表达式计算
c := 5
c++ // 正确:等价于 c = c + 1
// fmt.Println(c++) // 错误:不能直接用于输出等表达式
fmt.Println("c++ 后 =", c) // 输出 6
d := 8
d--
fmt.Println("d-- 后 =", d) // 输出 7
}整数除法会自动舍弃小数部分,若要保留小数需先转成 float64 类型;自增自减只能单独成句,不能写在 fmt.Println(a++) 这类表达式里,这是 Golang 独有的语法限制
赋值运算符
简化赋值逻辑
赋值运算符以 = 为基础,衍生出复合赋值(如 +=、*=),核心作用是简化变量赋值代码,提高可读性。
package main
import "fmt"
func main() {
// 基础赋值
var x int
x = 10
fmt.Println("基础赋值 x =", x) // 输出 10
// 复合赋值:等价于 变量 = 变量 运算符 右值
x += 5 // 等价于 x = x + 5
fmt.Println("x += 5 后 =", x) // 输出 15
x *= 2 // 等价于 x = x * 2
fmt.Println("x *= 2 后 =", x) // 输出 30
x %= 4 // 等价于 x = x % 4
fmt.Println("x %= 4 后 =", x) // 输出 2
// 多重赋值:Golang 特色,可交换变量值
y, z := 20, 30
y, z = z, y // 无需临时变量直接交换
fmt.Println("交换后 y =", y, "z =", z) // 输出 30 20
} 多重赋值在变量交换、函数返回多值接收时特别好用,比如接收 err 信息时的 data, err := func(),就是依托多重赋值实现的。
比较运算符
判断条件的“开关”
比较运算符用于判断两个值的关系,返回结果只有 true 或 false,是 if、for 等流程控制的核心。
package main
import "fmt"
func main() {
m, n := 15, 25
// 基本比较:== != > < >= <=
fmt.Println("m == n ?", m == n) // 输出 false
fmt.Println("m != n ?", m != n) // 输出 true
fmt.Println("m > n ?", m > n) // 输出 false
fmt.Println("m <= n ?", m <= n) // 输出 true
// 注意:Golang 中不能连写比较,如 10 < m < 20 是错误的
// 正确写法:使用逻辑运算符连接
fmt.Println("m 在 10-20 之间?", m > 10 && m < 20) // 输出 true
}不要像数学公式那样连写比较(如 5 < x < 10),Golang 不支持这种语法,必须用逻辑运算符 && 拆分。
逻辑运算符
组合条件判断
逻辑运算符有 3 个:&&(与)、||(或)、!(非),用于组合多个比较条件,核心特性是“短路求值”。
package main
import "fmt"
func main() {
p, q := true, false
// 逻辑与 &&:两边都为 true 才返回 true,左边为 false 则不执行右边
fmt.Println("p && q ?", p && q) // 输出 false
// 逻辑或 ||:左边为 true 则不执行右边,直接返回 true
fmt.Println("p || q ?", p || q) // 输出 true
// 逻辑非 !:取反
fmt.Println("!p ?", !p) // 输出 false
// 短路求值实例:右边函数不会执行
fmt.Println("短路测试:", q && testFunc()) // 输出 false,testFunc 未执行
}
func testFunc() bool {
fmt.Println("testFunc 执行了")
return true
}&& 左边为 false 时,右边代码直接跳过;|| 左边为 true 时,右边代码直接跳过。
这个特性可用于避免空指针报错,比如 obj != nil && obj.Name != "",若 obj 为空则不会执行后面的属性获取。
位运算符
操作二进制的“底层工具”
位运算符直接操作数值的二进制位,多用于底层开发、加密、性能优化等场景,开发者可能接触较少但必须了解基础用法。
package main
import "fmt"
func main() {
// 以 10(二进制 1010)和 3(二进制 0011)为例
s, t := 10, 3
// 按位与 &:对应位都为 1 则为 1
fmt.Println("s & t =", s & t) // 二进制 0010 → 输出 2
// 按位或 |:对应位有一个为 1 则为 1
fmt.Println("s | t =", s | t) // 二进制 1011 → 输出 11
// 按位异或 ^:对应位不同则为 1
fmt.Println("s ^ t =", s ^ t) // 二进制 1001 → 输出 9
// 左移 <<:整体左移,右边补 0(等价于乘以 2 的 n 次方)
fmt.Println("s << 1 =", s << 1) // 二进制 10100 → 输出 20(10*2)
// 右移 >>:整体右移,左边补符号位(等价于除以 2 的 n 次方)
fmt.Println("s >> 1 =", s >> 1) // 二进制 0101 → 输出 5(10/2)
}左移右移比乘法除法运算更快,比如 x << 2 比 x * 4 性能更高;异或运算可用于简单加密(两次异或同一值还原原数)。
总览详情:
| 位操作 | 含义 | 备注 | |
|---|---|---|---|
| & | 按位与 | 两个操作数对应的二进制位,都为1则为1,否则为0 | |
| | | 按位或 | 两个操作数对应的二进制位,有1则为1,否则为0 | |
| ~ | 按位非 | 两个操作数对应的二进制位,取反操作,1则为0,0则为1 | |
| ^ | 异或 | 两个操作数对应的二进制位,相同为0,相异为1 | |
| « | 左移 | 将二进制位全部左移n位,相当于乘以2的n次方,如1«6 相当于1×64=64 | |
| » | 右移 | 将二进制位全部右移n位,相当于除以2的n次方,如64»3 相当于64÷8=8 | |
运算符优先级与结合性
很多错误都是因为搞混优先级导致的,比如 1 + 2 * 3 结果是 7 不是 9。
下面整理了 Golang 运算符的优先级(从高到低),标红的是高频使用的:
| 优先级 | 运算符类型 | 具体运算符 | 结合性 |
|---|---|---|---|
| 1(最高) | 括号 | () | 从左到右 |
| 2 | 自增自减、取反 | ++、–、!、^(按位非) | 从右到左 |
| 3 | 算术运算符(乘除取模) | *、/、% | 从左到右 |
| 4 | 算术运算符(加减) | +、- | 从左到右 |
| 5 | 位运算符(移位) | «、» | 从左到右 |
| 6 | 比较运算符 | ==、!=、>、<、>=、<= | 从左到右 |
| 7 | 位运算符(与或异或) | &、^、| | 从左到右 |
| 8 | 逻辑运算符 | &&、| | 从左到右 |
| 9(最低) | 赋值运算符 | = | 从右到左 |
优先级记不准时,直接加括号!括号的优先级最高,能明确改变运算顺序,比如
(1 + 2) * 3比死记优先级更可靠。
常见问题
Q1. 自增自减用于表达式导致编译报错
问题代码:fmt.Println(a++) 或 b := a++
原因:Golang 规定自增自减只能作为独立语句,不能参与赋值、输出等表达式运算,这和 Java、C++ 不同。
解决办法:先执行自增自减,再使用变量
a := 5
a++ // 先自增
fmt.Println(a) // 正确,输出 6
b := a
a++ // 先赋值再自增
fmt.Println(b) // 正确,输出 6Q2. 逻辑运算符与位运算符混淆
问题代码:用 & 代替 && 判断条件:if a > 10 & b < 20 {}
原因:& 是位运算符,&& 是逻辑运算符,两者优先级不同(& 比 && 高),混用会导致逻辑错误。
解决办法:判断条件用逻辑运算符 &&、||,位运算只用于二进制操作。
a, b := 15, 18
// 正确:逻辑与判断条件
if a > 10 && b < 20 {
fmt.Println("条件成立")
}Q3. 优先级错误导致计算结果异常
问题代码:result := 10 + 20 * 3 - 5 想先算 10+20 和 3-5,结果得到 65 不是 295。
原因:乘法优先级高于加减,代码实际执行顺序是 10 + (20*3) -5。
解决办法:用括号明确指定运算顺序。
// 正确:先算括号内的加法和减法
result := (10 + 20) * (3 - 5)
fmt.Println(result) // 输出 -60(符合预期)Q4. 位运算右移时符号位问题
问题代码:负数右移后结果不符合预期:fmt.Println(-10 >> 1) 输出 -5 不是 5。
原因:Golang 中右移运算符 >> 是“算术右移”,负数的符号位(最高位)会补 1,而不是补 0。
解决办法:若要实现“逻辑右移”(不管正负都补 0),需先将负数转成无符号整数。
num := -10
// 算术右移:符号位补 1,结果 -5
fmt.Println(num >> 1)
// 逻辑右移:转无符号整数后右移,结果 9223372036854775803(二进制高位补 0)
fmt.Println(uint64(num) >> 1)总结
运算符看似基础,但想真正掌握就必须“练+避坑”:
基础用法靠实例代码巩固,比如写一段包含所有运算符的小脚本运行调试;
易错点靠总结记忆,比如自增自减的使用限制、短路特性的应用;
优先级记不准就加括号,不要靠“语感”写代码。
建议把把这些实例和错误整理到笔记里,遇到问题就翻出来对比,慢慢就形成了肌肉记忆。
如果你在实际使用中还遇到过其他运算符的坑,欢迎在评论区分享,咱们一起避坑~
版权声明
未经授权,禁止转载本文章。
如需转载请保留原文链接并注明出处。即视为默认获得授权。
未保留原文链接未注明出处或删除链接将视为侵权,必追究法律责任!
本文原文链接: https://fiveyoboy.com/articles/golang-bitwise-operators-guide/
备用原文链接: https://blog.fiveyoboy.com/articles/golang-bitwise-operators-guide/