Go 运算符
Go - 运算符
Section titled “Go - 运算符”运算符是一个符号,它告诉编译器执行特定的数学、逻辑或位操作。Go 语言提供了丰富的内置运算符,它们按以下类别划分:
- 算术运算符
- 关系运算符
- 逻辑运算符
- 位运算符
- 赋值运算符
- 其他运算符(如取地址
&和解引用*)
本教程将引导您了解 Go 语言中的各类运算符。
这些运算符执行数学计算。假设变量 a 的值为 10,变量 b 的值为 20:
示例代码:
package main
import "fmt"
func main() { a := 10 b := 20 var result int
result = a + b fmt.Printf("a + b = %d\n", result) // 输出: a + b = 30
result = a - b fmt.Printf("a - b = %d\n", result) // 输出: a - b = -10
result = a * b fmt.Printf("a * b = %d\n", result) // 输出: a * b = 200
result = b / a fmt.Printf("b / a = %d\n", result) // 输出: b / a = 2 (整型除法)
result = b % a fmt.Printf("b %% a = %d\n", result) // 输出: b % a = 0
// Go 中 ++/-- 是语句,不是表达式。 a++ // a 自增 1 (a 变为 11) fmt.Printf("After a++, a = %d\n", a) // 输出: After a++, a = 11
a-- // a 自减 1 (a 变为 10) fmt.Printf("After a--, a = %d\n", a) // 输出: After a--, a = 10}| 运算符 | 描述 | 示例 (a=10, b=20) |
|---|---|---|
| + | 加法:将两个操作数相加。 | a + b 结果为 30 |
| - | 减法:从第一个操作数中减去第二个操作数。 | a - b 结果为 -10 |
| * | 乘法:将两个操作数相乘。 | a * b 结果为 200 |
| / | 除法:用分子除以分母。如果两个操作数都是整数,结果为整数。 | b / a 结果为 2 |
| % | 取模:返回整数除法的余数。 | b % a 结果为 0 |
| ++ | 自增语句:将整数值增加一。不是表达式。 | a++ 将 a 变为 11 |
| — | 自减语句:将整数值减少一。不是表达式。 | a-- 将 a 变为 9 (如果初始 a=10) |
注意:Go 中的 ++ 和 -- 是语句,而不是表达式。您不能写 c := a++ 这样的代码。
这些运算符比较两个操作数并返回布尔值(true 或 false)。假设 a 的值为 10,b 的值为 20:
示例代码:
package main
import "fmt"
func main() { a := 10 b := 20
fmt.Printf("a == b: %t\n", a == b) // 输出: a == b: false fmt.Printf("a != b: %t\n", a != b) // 输出: a != b: true fmt.Printf("a > b: %t\n", a > b) // 输出: a > b: false fmt.Printf("a < b: %t\n", a < b) // 输出: a < b: true fmt.Printf("a >= b: %t\n", a >= b) // 输出: a >= b: false fmt.Printf("a <= b: %t\n", a <= b) // 输出: a <= b: true}| 运算符 | 描述 | 示例 (a=10, b=20) |
|---|---|---|
| == | 检查两个操作数的值是否相等。如果相等,则返回 true。 | (a == b) 为 false。 |
| != | 检查两个操作数的值是否不相等。如果不相等,则返回 true。 | (a != b) 为 true。 |
| > | 检查左操作数的值是否大于右操作数的值。 | (a > b) 为 false。 |
| < | 检查左操作数的值是否小于右操作数的值。 | (a < b) 为 true。 |
| >= | 检查左操作数的值是否大于或等于右操作数的值。 | (a >= b) 为 false。 |
| <= | 检查左操作数的值是否小于或等于右操作数的值。 | (a <= b) 为 true。 |
这些运算符作用于布尔操作数。假设 a 为 true,b 为 false:
示例代码:
package main
import "fmt"
func main() { a := true b := false
fmt.Printf("a && b: %t\n", a && b) // 输出: a && b: false fmt.Printf("a || b: %t\n", a || b) // 输出: a || b: true fmt.Printf("!a: %t\n", !a) // 输出: !a: false fmt.Printf("!(a && b): %t\n", !(a && b)) // 输出: !(a && b): true}| 运算符 | 描述 | 示例 (a=true, b=false) |
|---|---|---|
| && | 逻辑 AND。如果两个操作数都为 true,则返回 true。 | (a && b) 为 false。 |
| || | 逻辑 OR。如果至少一个操作数为 true,则返回 true。 | (a || b) 为 true。 |
| ! | 逻辑 NOT。反转操作数的逻辑状态。如果 a 为 true,则 !a 为 false。 | !(a && b) 为 true。 |
位运算符在二进制级别对整型操作数执行操作。考虑 AND (&)、OR (|) 和 XOR (^) 的真值表:
| p | q | p & q | p | q | p ^ q |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 |
| 0 | 1 | 0 | 1 | 1 |
| 1 | 1 | 1 | 1 | 0 |
| 1 | 0 | 0 | 1 | 1 |
假设 a = 60 (二进制 0011 1100) 和 b = 13 (二进制 0000 1101):
a = 0011 1100b = 0000 1101-----------------a & b = 0000 1100 (12)a | b = 0011 1101 (61)a ^ b = 0011 0001 (49)a &^ b = 0011 0000 (48) (Bit Clear)Go 中的位运算符 NOT (^) 实际上是 XOR。要执行按位补码操作(类似于 C 语言的 ~),您需要与掩码进行 XOR(例如,对于 32 位整数,m = a ^ 0xFFFFFFFF)。对于无符号整数,如果上下文暗示了位宽,通常可以使用 ^a,或者使用 math.MaxUintXX。
示例代码:
package main
import "fmt"
func main() { var a uint = 60 // 0011 1100 var b uint = 13 // 0000 1101 var result uint
result = a & b fmt.Printf("a & b = %d (binary %08b)\n", result, result) // 输出: a & b = 12 (二进制 00001100)
result = a | b fmt.Printf("a | b = %d (binary %08b)\n", result, result) // 输出: a | b = 61 (二进制 00111101)
result = a ^ b fmt.Printf("a ^ b = %d (binary %08b)\n", result, result) // 输出: a ^ b = 49 (二进制 00110001)
result = a << 2 fmt.Printf("a << 2 = %d (binary %08b)\n", result, result) // 输出: a << 2 = 240 (二进制 11110000)
result = a >> 2 fmt.Printf("a >> 2 = %d (binary %08b)\n", result, result) // 输出: a >> 2 = 15 (二进制 00001111)
// 位清零 (AND NOT) result = a &^ b // 清除 'a' 中在 'b' 中设置的位 fmt.Printf("a &^ b = %d (binary %08b)\n", result, result) // 输出: a &^ b = 48 (二进制 00110000)}| 运算符 | 描述 | 示例 (a=60, b=13, 无符号) |
|---|---|---|
| & | 按位 AND:如果位在两个操作数中都存在,则将该位设置为 1。 | a & b 结果为 12 (0000 1100) |
| | | 按位 OR:如果位在任一操作数中存在,则将该位设置为 1。 | a | b 结果为 61 (0011 1101) |
| ^ | 按位 XOR:如果位仅在一个操作数中设置(不同),则将该位设置为 1。 | a ^ b 结果为 49 (0011 0001) |
| << | 左移:将左操作数的位向左移动由右操作数指定的位数。用零填充空位。 | a << 2 结果为 240 (1111 0000) |
| >> | 右移:将左操作数的位向右移动由右操作数指定的位数。行为取决于是有符号还是无符号类型(算术移位 vs 逻辑移位)。 | a >> 2 结果为 15 (对于无符号 a 是 0000 1111) |
| &^ | 位清零 (AND NOT):清除左操作数中在右操作数中设置的位(相当于 a & (^b))。 | a &^ b 结果为 48 (0011 0000) |
这些运算符用于给变量赋值,通常会将算术或位操作与赋值结合起来。
示例代码:
package main
import "fmt"
func main() { a := 10 c := 5
c += a // c = c + a = 5 + 10 = 15 fmt.Printf("c += a -> c = %d\n", c)
c = 5 // 重置 c c -= a // c = c - a = 5 - 10 = -5 fmt.Printf("c -= a -> c = %d\n", c)
c = 5 // 重置 c c *= a // c = c * a = 5 * 10 = 50 fmt.Printf("c *= a -> c = %d\n", c)
c = 50 // 重置 c c /= a // c = c / a = 50 / 10 = 5 fmt.Printf("c /= a -> c = %d\n", c)
c = 51 // 重置 c c %= a // c = c % a = 51 % 10 = 1 fmt.Printf("c %%= a -> c = %d\n", c)
// 位赋值运算符的类似示例 (<<=, >>=, &=, ^=, |=, &^=) d := uint(60) // 位操作使用 uint 类型 d <<= 2 // d = d << 2 fmt.Printf("d <<= 2 -> d = %d\n", d)}| 运算符 | 描述 | 示例 |
|---|---|---|
| = | 简单赋值:将右侧的值赋给左侧操作数。 | c = a + b 将 a + b 的值赋给 c。 |
| += | 加法赋值:将右操作数加到左操作数上,并将结果赋给左操作数。 | c += a 等同于 c = c + a。 |
| -= | 减法赋值:从左操作数中减去右操作数,并将结果赋给左操作数。 | c -= a 等同于 c = c - a。 |
| *= | 乘法赋值:将左操作数乘以右操作数,并将结果赋给左操作数。 | c *= a 等同于 c = c * a。 |
| /= | 除法赋值:将左操作数除以右操作数,并将结果赋给左操作数。 | c /= a 等同于 c = c / a。 |
| %= | 取模赋值:对两个操作数取模,并将结果赋给左操作数。 | c %= a 等同于 c = c % a。 |
| <<= | 左移赋值。 | c <<= 2 等同于 c = c << 2。 |
| >>= | 右移赋值。 | c >>= 2 等同于 c = c >> 2。 |
| &= | 按位 AND 赋值。 | c &= 2 等同于 c = c & 2。 |
| ^= | 按位 XOR 赋值。 | c ^= 2 等同于 c = c ^ 2。 |
| |= | 按位 OR 赋值。 | c |= 2 等同于 c = c | 2。 |
| &^= | 位清零赋值。 | c &^= 2 等同于 c = c &^ 2。 |
Go 语言包含与内存地址和指针相关的运算符:
示例代码:
package main
import "fmt"
func main() { a := 100 var ptr *int // 声明一个指向整数的指针
ptr = &a // 将 'a' 的内存地址赋给指针变量 'ptr' fmt.Printf("Address of a: %p\n", &a) // 输出: Address of a: 0x... (实际地址) fmt.Printf("Value stored in ptr: %p\n", ptr) // 输出: Value stored in ptr: 0x... (相同的地址)
// 解引用指针以获取值 fmt.Printf("Value pointed to by ptr (*ptr): %d\n", *ptr) // 输出: Value pointed to by ptr (*ptr): 100}| 运算符 | 描述 | 示例 |
|---|---|---|
| & | 取地址运算符:返回变量的内存地址。 | &a 获取变量 a 的实际内存地址。 |
| * | 解引用运算符(与指针一起使用时):访问指针所持有的内存地址处存储的值。 | *ptr 获取 ptr 指向的地址处存储的值。 |
注意:Go 语言不像 C 或 Java 那样有三元运算符(? :)。您必须使用标准的 if-else 语句。
sizeof 的概念由 unsafe 包中的 unsafe.Sizeof 函数处理,但除非处理底层操作或需要互操作性,否则通常不建议使用它。
Go 语言中的运算符优先级
Section titled “Go 语言中的运算符优先级”运算符优先级定义了表达式中操作执行的顺序。优先级高的运算符会先被求值。例如,乘法的优先级高于加法。
示例:x := 7 + 3 * 2。在这里,由于 * 的优先级较高,先计算 3 * 2 (结果为 6),然后计算 7 + 6。因此,x 的值是 13,而不是 20。
同一优先级级别的运算符通常从左到右求值(请查看结合性)。可以使用括号 () 来覆盖优先级。
Go 运算符优先级(从高到低):
| 类别 | 运算符 | 结合性 |
|---|---|---|
| 一元运算符 | + - ! ^ * & <- (一元运算符、指针操作、通道接收) | 无 (最高) |
| 乘法/位移/按位 | * / % << >> & &^ | 从左到右 |
| 加法/按位 | + - | ^ | 从左到右 |
| 比较 | == != < <= > >= | 从左到右 |
| 逻辑 AND | && | 从左到右 |
| 逻辑 OR | || | 从左到右 |
注意:赋值操作在对右侧表达式求值后进行。上面的优先级表是简化的;要获取完整详情,请参考官方 Go 语言规范。