Go 运算符
最后修改时间 2024 年 4 月 11 日
在本文中,我们介绍 Go 运算符。我们展示了如何使用运算符创建表达式。
运算符是一个特殊的符号,表示执行某个过程。编程语言中的运算符取自数学。程序员处理数据。运算符用于处理数据。操作数是运算符的一个输入(参数)。
表达式由操作数和运算符构成。表达式中的运算符指示要对操作数应用哪些操作。表达式中运算符的求值顺序由运算符的优先级和结合性决定。
一个运算符通常有一个或两个操作数。只使用一个操作数的运算符称为一元运算符。使用两个操作数的运算符称为二元运算符。
某些运算符可以在不同上下文中重复使用。例如,+ 运算符可以在不同情况下使用:它可以对数字进行加法运算、连接字符串,或者表示数字的符号。我们称该运算符是重载的。
Go 符号运算符
有两个符号运算符:+ 和 -。它们用于表示或改变值的符号。
package main
import "fmt"
func main() {
fmt.Println(2)
fmt.Println(+2)
fmt.Println(-2)
}
+ 和 - 符号表示值的符号。加号可以用来表示我们有一个正数。它可以被省略,并且在大多数情况下都被省略了。
package main
import "fmt"
func main() {
var a = 1
fmt.Println(-a)
fmt.Println(-(-a))
}
减号会改变值的符号。
Go 赋值运算符
赋值运算符 = 将一个值赋给一个变量。变量是值的占位符。在数学中,= 运算符有不同的含义。在等式中,= 运算符是相等运算符。等式的左边等于右边。
var x = 1
在这里,我们将一个数字赋给 x 变量。
x = x + 1
这个表达式在数学上没有意义,但在编程中是合法的。该表达式将 x 变量加 1。右侧等于 2,然后 2 被赋给 x。
3 = x
这行代码会导致语法错误。我们不能将值赋给字面量。
x := 2
Go 有一个简短的变量声明运算符 :=;它在一个步骤中声明变量并赋值。x := 2 等同于 var x = 2。
Go 递增和递减运算符
在编程中,我们经常将一个值加一或减一。Go 为此提供了两个方便的运算符:++ 和 --。
x++ // x = x + 1 y-- // y = y - 1
package main
import "fmt"
func main() {
x := 6
x++
x++
fmt.Println(x)
x--
fmt.Println(x)
}
在上面的示例中,我们演示了这两个运算符的用法。
x := 6 x++ x++
我们将 x 变量初始化为 6。然后我们对 x 加一两次。现在变量的值是 8。
x--
我们使用了递减运算符。现在变量的值是 7。
$ go run inc_dec.go 8 7
Go 复合赋值运算符
复合赋值运算符由两个运算符组成。它们是简写运算符。
a = a + 3 a += 3
+= 复合运算符是这些简写运算符之一。上面的两个表达式是相等的。将值 3 加到 a 变量上。
其他复合运算符包括
-= *= /= %= &= |= <<= >>=
package main
import "fmt"
func main() {
var a int = 1
a = a + 1
fmt.Println(a)
a += 5
fmt.Println(a)
a *= 3
fmt.Println(a)
}
在代码示例中,我们使用了两个复合运算符。
var a int = 1 a = a + 1
a 变量被初始化为一。使用非简写符号将 1 加到该变量上。
a += 5
使用 += 复合运算符,我们将 5 加到 a 变量上。该语句等同于 a = a + 5。
a *= 3
使用 *= 运算符,将 a 乘以 3。该语句等同于 a = a * 3。
$ go run compound_operators.go 2 7 21
Go 算术运算符
下面是 Go 中的算术运算符表。
| 符号 | 名称 |
|---|---|
+ | 加法 |
- | 减法 |
* | 乘法 |
| / | 除法 |
% | 余数 |
下面的示例展示了算术运算。
package main
import "fmt"
func main() {
var a = 10
var b = 11
var c = 12
var add = a + b + c
var sb = c - a
var mult = a * b
var div = c / 3
var rem = c % a
fmt.Println(add)
fmt.Println(sb)
fmt.Println(mult)
fmt.Println(div)
fmt.Println(rem)
}
在前面的示例中,我们使用了加法、减法、乘法、除法和取余运算。这些都与数学中的一样熟悉。
var rem = c % a
% 运算符称为余数或模运算符。它用于找出两个数相除的余数。例如,9 % 4,9 模 4 等于 1,因为 4 能整除 9 两次,余数为 1。
$ go run arithmetic.go 33 2 110 4 2
接下来我们将展示整数除法和浮点数除法的区别。
package main
import "fmt"
func main() {
c := 5 / 2
fmt.Println(c)
d := 5 / 2.0
fmt.Println(d)
}
在前面的示例中,我们对两个数进行了除法运算。
c := 5 / 2 fmt.Println(c)
在这段代码中,我们进行了整数除法。除法运算的返回值是整数。当我们对两个整数进行除法时,结果是一个整数。
d := 5 / 2.0 fmt.Println(d)
如果其中一个值是双精度浮点数或单精度浮点数,我们就执行浮点数除法。在本例中,第二个操作数是双精度浮点数,所以结果也是双精度浮点数。
$ go run division.go 2 2.5
Go 布尔运算符
在 Go 中,我们有三个逻辑运算符。
| 符号 | 名称 |
|---|---|
&& | 逻辑与 |
|| | 逻辑或 |
! | 逻辑非 |
布尔运算符也称为逻辑运算符。
package main
import "fmt"
func main() {
var x = 3
var y = 8
fmt.Println(x == y)
fmt.Println(y > x)
if y > x {
fmt.Println("y is greater than x")
}
}
许多表达式会产生布尔值。例如,布尔值用于条件语句。
fmt.Println(x == y) fmt.Println(y > x)
关系运算符始终产生布尔值。这两行打印 false 和 true。
if y > x {
fmt.Println("y is greater than x")
}
只有当括号内的条件满足时,才会执行 if 语句的主体。y > x 返回 true,因此消息 "y is greater than x" 会打印到终端。
true 和 false 关键字在 Go 中表示布尔字面量。
package main
import "fmt"
func main() {
var a = true && true
var b = true && false
var c = false && true
var d = false && false
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
fmt.Println(d)
}
代码示例展示了逻辑与 (&&) 运算符。仅当两个操作数都为 true 时,它才为 true。
$ go run and_operator.go true false false false
只有一个表达式的结果为 true。
逻辑或 (||) 运算符当任一操作数为 true 时,结果为 true。
package main
import "fmt"
func main() {
var a = true || true
var b = true || false
var c = false || true
var d = false || false
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
fmt.Println(d)
}
如果运算符的任一边为 true,则操作的结果为 true。
$ go run or_operator.go true true true false
四分之三的表达式结果为 true。
否定运算符 ! 将 true 变为 false,将 false 变为 true。
package main
import "fmt"
func main() {
fmt.Println(!true)
fmt.Println(!false)
fmt.Println(!(4 < 3))
}
该示例展示了否定运算符的实际应用。
$ go run negation_operator.go false true true
Go 比较运算符
比较运算符用于比较值。这些运算符始终产生布尔值。
| 符号 | 含义 |
|---|---|
< | 小于 |
<= | 小于或等于 |
> | 大于 |
>= | 大于或等于 |
== | 等于 |
!= | 不等于 |
比较运算符也称为关系运算符。
package main
import "fmt"
func main() {
fmt.Println(3 < 4)
fmt.Println(3 == 4)
fmt.Println(4 >= 3)
fmt.Println(4 != 3)
}
在代码示例中,我们有四个表达式。这些表达式比较整数值。每个表达式的结果要么是 true,要么是 false。在 Go 中,我们使用 == 来比较数字。(像 Ada、Visual Basic 或 Pascal 这样的某些语言使用 = 来比较数字。)
Go 位运算符
十进制数对人类来说是自然的。二进制数是计算机的原生形式。二进制、八进制、十进制或十六进制符号只是同一数字的表示法。位运算符处理二进制数的位。
| 符号 | 含义 |
|---|---|
^ | 按位异或 |
& | 按位与 |
| | 按位或 |
&^ | 位清除(与非) |
<< | 左移 |
>> | 右移 |
按位与运算符对两个数字执行逐位比较。只有当操作数中对应的位都为 1 时,结果的该位才为 1。
00110 & 00011 = 00010
第一个数字是 6 的二进制表示,第二个是 3,结果是 2。
fmt.Println(6 & 3) // prints 2 fmt.Println(3 & 6) // prints 2
按位或运算符对两个数字执行逐位比较。当操作数中对应的位任一为 1 时,结果的该位为 1。
00110 | 00011 = 00111
结果是 00110 或十进制的 7。
fmt.Println(6 | 3) // prints 7 fmt.Println(3 | 6) // prints 7
按位异或运算符对两个数字执行逐位比较。当操作数中对应的位任一为 1 但不是两者都为 1 时,结果的该位为 1。
00110 ^ 00011 = 00101
结果是 00101 或十进制的 5。
fmt.Println(6 ^ 3) // prints 5 fmt.Println(3 ^ 6) // prints 5
Go 指针运算符
在 Go 中,& 是地址运算符,* 是指针间接运算符。
package main
import "fmt"
func main() {
var count int = 4
fmt.Println(count)
var pv = &count
*pv = 3
fmt.Println(pv)
fmt.Println(*pv)
}
在代码示例中,我们演示了这两个运算符。
var count int = 4
定义了一个整数变量。
var pv = &count
我们获取 count 变量的地址;我们创建一个指向该变量的指针。
*pv = 3
通过指针解引用,我们修改了 count 的值。
fmt.Println(*pv)
再次通过指针解引用,我们将指针指向的值打印出来。
$ go run pointer_op.go 4 0xc0000140f8 3
Go 通道运算符
通道是类型的通道,我们可以使用通道运算符 <- 在其中发送和接收值。
package main
import "fmt"
func main() {
messages := make(chan string)
go func() { messages <- "hello" }()
msg := <-messages
fmt.Println(msg)
}
示例介绍了通道运算符。
go func() { messages <- "hello" }()
我们将一个值发送到通道。
msg := <-messages
我们从通道接收一个值。
Go 运算符优先级
运算符优先级告诉我们哪些运算符首先被求值。优先级级别对于避免表达式中的歧义是必需的。
以下表达式的结果是 28 还是 40?
3 + 5 * 5
就像在数学中一样,乘法运算符的优先级高于加法运算符。所以结果是 28。
(3 + 5) * 5
要更改求值顺序,我们可以使用括号。括号内的表达式总是首先被求值。上述表达式的结果是 40。
package main
import "fmt"
func main() {
fmt.Println(3 + 5*5)
fmt.Println((3 + 5) * 5)
fmt.Println(!true || true)
fmt.Println(!(true || true))
}
在这段代码示例中,我们展示了几个表达式。每个表达式的结果取决于优先级级别。
fmt.Println(3 + 5*5)
这行打印 28。乘法运算符的优先级高于加法。首先计算 5 * 5 的乘积,然后加上 3。
fmt.Println((3 + 5) * 5)
通过使用圆括号可以改变表达式的求值顺序。在这种情况下,先计算 3 + 5,然后将该值乘以 5。这行打印 40。
fmt.Println(!true || true)
在这种情况下,否定运算符的优先级高于按位或。首先,将初始的 true 值取反为 false,然后 | 运算符将 false 和 true 组合起来,最终得到 true。
$ go run precedence.go 28 40 true false
结合律
有时优先级不足以确定表达式的结果。还有另一个规则称为结合性。运算符的结合性决定了具有相同优先级级别的运算符的求值顺序。
9 / 3 * 3
这个表达式的结果是 9 还是 1?乘法、除法和模运算符是从左到右结合的。所以表达式的求值方式是:(9 / 3) * 3 结果是 9。
算术、布尔和关系运算符是从左到右结合的。三元运算符、递增、递减、一元加减、否定、按位非、类型转换、对象创建运算符是从右到左结合的。
package main
import "fmt"
func main() {
var j = 0
j *= 3 + 1
fmt.Println(j)
}
在代码示例中,我们使用结合律来确定表达式的结果。
var j = 0 j *= 3 + 1
复合赋值运算符是从右到左结合的。我们可能期望结果是 1。但实际结果是 0。这是由于结合律。右侧的表达式首先被求值,然后应用复合赋值运算符。
来源
The Go Programming Language Specification
在本文中,我们介绍了 Go 运算符。