1. 引言
运算符是任何编程语言的基础构建块,用于对变量和值执行操作。Go 语言提供了一套丰富且清晰的运算符,涵盖了算术、比较、逻辑、位运算、赋值等多个方面。掌握这些运算符是编写高效、可读 Go 代码的关键第一步。本文将系统性地介绍 Go 语言中的所有运算符,并通过代码示例帮助你深入理解其用法和注意事项。
2. 算术运算符
算术运算符用于执行基本的数学运算。
| 运算符 | 描述 | 示例 |
|---|---|---|
+ |
加法 | a + b |
- |
减法 | a - b |
* |
乘法 | a * b |
/ |
除法 | a / b |
% |
取模(求余) | a % b |
++ |
自增 | a++ |
-- |
自减 | a-- |
重要说明:
++和--在 Go 中是语句 ,而非表达式。这意味着它们不能出现在赋值语句的右侧,也不能与其他运算符混合使用。例如,b = a++或if a++ > 0在 Go 中是非法的。- Go 语言没有
+运算符用于字符串连接,而是使用+运算符。例如:"Hello, " + "World!"。
示例代码:
go
package main
import "fmt"
func main() {
a := 10
b := 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
a++ // a 变为 11
fmt.Println("a++ =", a)
b-- // b 变为 2
fmt.Println("b-- =", b)
// 字符串"加法"
str1 := "Go"
str2 := "Lang"
fmt.Println(str1 + " " + str2) // Go Lang
}
3. 关系运算符(比较运算符)
关系运算符用于比较两个值,返回一个布尔值 (true 或 false)。
| 运算符 | 描述 | 示例 |
|---|---|---|
== |
等于 | a == b |
!= |
不等于 | a != b |
> |
大于 | a > b |
< |
小于 | a < b |
>= |
大于等于 | a >= b |
<= |
小于等于 | a <= b |
示例代码:
go
package main
import "fmt"
func main() {
x := 5
y := 10
fmt.Println("x == y?", x == y) // false
fmt.Println("x != y?", x != y) // true
fmt.Println("x > y?", x > y) // false
fmt.Println("x < y?", x < y) // true
fmt.Println("x >= 5?", x >= 5) // true
fmt.Println("y <= 10?", y <= 10) // true
}
4. 逻辑运算符
逻辑运算符用于组合或反转布尔条件。
| 运算符 | 描述 | 示例 |
|---|---|---|
&& |
逻辑与 (AND)。两边都为 true 时结果为 true。 |
a && b |
| ` | ` | |
! |
逻辑非 (NOT)。反转布尔值。 | !a |
Go 中的逻辑运算符支持短路求值:
- 对于
&&,如果左边表达式为false,则右边表达式不会被计算。 - 对于
||,如果左边表达式为true,则右边表达式不会被计算。
示例代码:
go
package main
import "fmt"
func main() {
a := true
b := false
fmt.Println("a && b =", a && b) // false
fmt.Println("a || b =", a || b) // true
fmt.Println("!a =", !a) // false
fmt.Println("!b =", !b) // true
// 短路求值示例
var count int
// 由于 false && ...,increment() 永远不会被调用
if false && increment(&count) {
// 不会执行
}
fmt.Println("Count after false &&:", count) // 0
// 由于 true || ...,increment() 永远不会被调用
if true || increment(&count) {
// 会执行
}
fmt.Println("Count after true ||:", count) // 0 (仍然为0)
}
func increment(c *int) bool {
*c++
return true
}
5. 位运算符
位运算符在整数的二进制位级别进行操作。
| 运算符 | 描述 | 示例 |
|---|---|---|
& |
按位与 (AND)。两位都为1时结果为1。 | a & b |
| ` | ` | 按位或 (OR)。至少一位为1时结果为1。 |
^ |
按位异或 (XOR)。两位不同时结果为1。 | a ^ b |
&^ |
位清空 (AND NOT)。将 b 中为1的位,在 a 中对应位清零。 |
a &^ b |
<< |
左移。左操作数按位左移右操作数指定的位数。 | a << n |
>> |
右移。左操作数按位右移右操作数指定的位数。 | a >> n |
示例代码:
go
package main
import "fmt"
func main() {
var a uint = 60 // 二进制: 0011 1100
var b uint = 13 // 二进制: 0000 1101
fmt.Printf("a = %d, 二进制: %08b\n", a, a)
fmt.Printf("b = %d, 二进制: %08b\n", b, b)
fmt.Printf("a & b = %d, 二进制: %08b\n", a&b, a&b) // 12 (0000 1100)
fmt.Printf("a | b = %d, 二进制: %08b\n", a|b, a|b) // 61 (0011 1101)
fmt.Printf("a ^ b = %d, 二进制: %08b\n", a^b, a^b) // 49 (0011 0001)
fmt.Printf("a &^ b = %d, 二进制: %08b\n", a&^b, a&^b) // 48 (0011 0000) 清空b中为1的位
fmt.Printf("a << 2 = %d, 二进制: %08b\n", a<<2, a<<2) // 240 (1111 0000)
fmt.Printf("a >> 2 = %d, 二进制: %08b\n", a>>2, a>>2) // 15 (0000 1111)
}
6. 赋值运算符
赋值运算符用于为变量赋值。
| 运算符 | 示例 | 等价于 |
|---|---|---|
= |
a = 5 |
a = 5 |
+= |
a += 3 |
a = a + 3 |
-= |
a -= 3 |
a = a - 3 |
*= |
a *= 3 |
a = a * 3 |
/= |
a /= 3 |
a = a / 3 |
%= |
a %= 3 |
a = a % 3 |
&= |
a &= 3 |
a = a & 3 |
| ` | =` | `a |
^= |
a ^= 3 |
a = a ^ 3 |
&^= |
a &^= 3 |
a = a &^ 3 |
<<= |
a <<= 3 |
a = a << 3 |
>>= |
a >>= 3 |
a = a >> 3 |
示例代码:
go
package main
import "fmt"
func main() {
var a int = 10
a += 5 // a = 15
fmt.Println("a += 5 ->", a)
a -= 3 // a = 12
fmt.Println("a -= 3 ->", a)
a *= 2 // a = 24
fmt.Println("a *= 2 ->", a)
a /= 4 // a = 6
fmt.Println("a /= 4 ->", a)
a %= 4 // a = 2
fmt.Println("a %= 4 ->", a)
var b uint = 0b1111 // 15
b &= 0b1010 // b = 10 (0b1010)
fmt.Printf("b &= 0b1010 -> %b (%d)\n", b, b)
}
7. 其他运算符
| 运算符 | 描述 | 示例 |
|---|---|---|
& |
取地址运算符。返回变量的内存地址。 | &a |
* |
指针解引用运算符。返回指针指向地址的值。 | *ptr |
<- |
通道运算符。用于向通道发送或从通道接收值。 | ch <- v (发送), v := <-ch (接收) |
示例代码:
go
package main
import "fmt"
func main() {
// 1. 取地址与解引用
x := 42
ptr := &x // ptr 是一个指向 x 的指针
fmt.Println("x 的值:", x)
fmt.Println("x 的地址:", ptr)
fmt.Println("通过指针访问 x 的值:", *ptr)
*ptr = 100 // 通过指针修改 x 的值
fmt.Println("修改后 x 的值:", x)
// 2. 通道运算符 (简单示例)
ch := make(chan int, 1) // 创建一个缓冲大小为1的通道
ch <- 99 // 向通道发送值 99
received := <-ch // 从通道接收值
fmt.Println("从通道接收到的值:", received)
}
8. 运算符优先级
当表达式中包含多个运算符时,运算顺序由运算符的优先级决定。优先级高的运算符先计算。如果优先级相同,则按从左到右的顺序计算(赋值运算符除外,它是从右向左结合)。
下表列出了 Go 运算符的优先级,从高到低排列:
| 优先级 | 运算符 |
|---|---|
| 5 | * / % << >> & &^ |
| 4 | + - ` |
| 3 | == != < <= > >= |
| 2 | && |
| 1 | ` |
注意:
- 可以使用括号
()来显式地改变运算顺序,括号内的表达式总是最先计算。 - 赋值运算符(如
=、+=)的优先级最低,且是右结合的。
示例:
go
result := 5 + 3*2 // 先算 3*2=6,再算 5+6=11
fmt.Println(result) // 11
result2 := (5 + 3) * 2 // 先算括号 5+3=8,再算 8*2=16
fmt.Println(result2) // 16
a, b := 1, 2
a += b * 3 // 等价于 a = a + (b * 3) -> a = 1 + 6 = 7
fmt.Println(a) // 7
9. 总结
Go 语言的运算符设计简洁而强大,遵循了 C 语言家族的传统,同时去除了一些容易导致错误的特性(如将 ++/-- 限制为语句)。理解并熟练运用这些运算符是进行 Go 编程的基础。记住以下几点关键区别:
++/--是语句,不能参与表达式运算。- 字符串连接使用
+运算符。 - 逻辑运算符
&&和||支持短路求值。 - Go 特有的
&^(位清空)运算符非常实用。 - 使用括号来明确复杂表达式的计算顺序。
建议读者在 IDE 或编辑器中多练习这些运算符的组合使用,以加深理解。