ZetCode

Go 运算符

最后修改时间 2024 年 4 月 11 日

在本文中,我们介绍 Go 运算符。我们展示了如何使用运算符创建表达式。

运算符是一个特殊的符号,表示执行某个过程。编程语言中的运算符取自数学。程序员处理数据。运算符用于处理数据。操作数是运算符的一个输入(参数)。

表达式由操作数和运算符构成。表达式中的运算符指示要对操作数应用哪些操作。表达式中运算符的求值顺序由运算符的优先级结合性决定。

一个运算符通常有一个或两个操作数。只使用一个操作数的运算符称为一元运算符。使用两个操作数的运算符称为二元运算符

某些运算符可以在不同上下文中重复使用。例如,+ 运算符可以在不同情况下使用:它可以对数字进行加法运算、连接字符串,或者表示数字的符号。我们称该运算符是重载的。

Go 符号运算符

有两个符号运算符:+-。它们用于表示或改变值的符号。

sign_operators.go
package main

import "fmt"

func main() {

    fmt.Println(2)
    fmt.Println(+2)
    fmt.Println(-2)
}

+- 符号表示值的符号。加号可以用来表示我们有一个正数。它可以被省略,并且在大多数情况下都被省略了。

minus_sign.go
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
inc_dec.go
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 变量上。

其他复合运算符包括

-=   *=   /=   %=   &=   |=   <<=   >>=
compound_operators.go
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 中的算术运算符表。

符号名称
+加法
-减法
*乘法
/除法
%余数

下面的示例展示了算术运算。

arithmetic.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

接下来我们将展示整数除法和浮点数除法的区别。

division.go
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 中,我们有三个逻辑运算符。

符号名称
&&逻辑与
||逻辑或
!逻辑非

布尔运算符也称为逻辑运算符。

boolean_exp.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" 会打印到终端。

truefalse 关键字在 Go 中表示布尔字面量。

and_operator.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。

or_operator.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 or_operator.go
true
true
true
false

四分之三的表达式结果为 true。

否定运算符 ! 将 true 变为 false,将 false 变为 true。

negation_operator.go
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 比较运算符

比较运算符用于比较值。这些运算符始终产生布尔值。

符号含义
<小于
<=小于或等于
>大于
>=大于或等于
==等于
!=不等于

比较运算符也称为关系运算符。

comparison_operators.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 中,& 是地址运算符,* 是指针间接运算符。

pointer_op.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 通道运算符

通道是类型的通道,我们可以使用通道运算符 <- 在其中发送和接收值。

channel_op.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。

operator_precedence.go
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。

算术、布尔和关系运算符是从左到右结合的。三元运算符、递增、递减、一元加减、否定、按位非、类型转换、对象创建运算符是从右到左结合的。

associativity.go
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 运算符。

作者

我的名字是 Jan Bodnar,我是一名充满热情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。至今,我已撰写了 1400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出所有 Go 教程