Go 语言完全指南 / 05 - 运算符:算术、逻辑、位运算
05 - 运算符
5.1 算术运算符
| 运算符 | 说明 | 示例 | 结果 |
|---|
+ | 加 | 3 + 2 | 5 |
- | 减 | 3 - 2 | 1 |
* | 乘 | 3 * 2 | 6 |
/ | 除 | 7 / 2 | 3(整数除法) |
% | 取模 | 7 % 2 | 1 |
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 == 3 → true |
!= | 不等于 | 3 != 2 → true |
< | 小于 | 2 < 3 → true |
<= | 小于等于 | 3 <= 3 → true |
> | 大于 | 3 > 2 → true |
>= | 大于等于 | 3 >= 4 → false |
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 则不求右 |
! | 逻辑非 | !true → false |
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 & 0b1010 → 0b1000 |
| | 按位或 | 0b1100 | 0b1010 → 0b1110 |
^ | 按位异或 | 0b1100 ^ 0b1010 → 0b0110 |
&^ | 位清除(AND NOT) | 0b1100 &^ 0b1010 → 0b0100 |
<< | 左移 | 1 << 3 → 8 |
>> | 右移 | 8 >> 2 → 2 |
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)
}
🏢 业务场景
- 权限管理:用位运算组合和检查权限标志
- IP 地址处理:位运算计算子网掩码、网络地址
- 状态标志:用位掩码管理多个布尔状态
- 数据压缩:位运算实现紧凑的数据编码
- 哈希计算:使用
^ 和 << 实现简单哈希
📖 扩展阅读