Go语言提供了一系列用于执行各种运算操作的运算符,用以表示数据的运算、赋值和比较等。以下是一些常见的Go语言运算符及其用法:
算数运算符
算术运算符用于执行基本的数学运算,如加法、减法、乘法、除法和取模等。这些运算符可以直接应用于数值类型的变量或常量上,比如整型(int、int8、int16、int32、int64、uint、uint8、uint16、uint32、uint64、uintptr)、浮点型(float32、float64)以及复数类型(complex64、complex128)。
自增和自减不是算数运算符,是单独的语句。
-
加法运算符 (
+):
用于将两个数相加。如果操作数都是整数,结果也是整数;如果操作数中有浮点数,则结果是浮点数。a := 5b := 3sum := a + b // 结果为 8c := 3.5d := 2.5sumFloat := c + d // 结果为 6.0 -
减法运算符 (
-):
用于从一个数中减去另一个数。操作数的类型规则与加法相同。a := 5b := 3diff := a - b // 结果为 2c := 3.5d := 2.5diffFloat := c - d // 结果为 1.0 -
乘法运算符 (
*):
用于将两个数相乘。操作数的类型规则与加法相同。a := 5b := 3product := a * b // 结果为 15c := 3.5d := 2.0productFloat := c * d // 结果为 7.0 -
除法运算符 (
/):
用于将第一个数除以第二个数。如果两个操作数都是整数,则结果也是整数(结果向零取整)。如果操作数中有浮点数,则结果是浮点数。a := 5b := 2quotientInt := a / b // 结果为 2c := 5.0d := 2.0quotientFloat := c / d // 结果为 2.5 -
取模运算符 (
%):
用于求两个整数相除后的余数。注意,取模运算符不能用于浮点数。a := 5b := 2remainder := a % b // 结果为 1
比较运算符
比较运算符(也称为关系运算符)用于比较两个值,并根据比较结果返回布尔值true或false。这些运算符主要用于条件表达式中,如if语句、for循环的条件部分以及逻辑运算符(如&&和||)的操作数
-
等于 (
==): 检查两个值是否相等。如果相等,结果为true;否则为false。a := 5b := 5fmt.Println(a==b) true
if a == b {fmt.Println("a equals b")} -
不等于 (
!=): 检查两个值是否不相等。如果不相等,结果为true;否则为false。a := 5b := 6if a != b {fmt.Println("a does not equal b")} -
小于 (
<): 检查左边的值是否小于右边的值。如果是,结果为true;否则为false。a := 3b := 5if a < b {fmt.Println("a is less than b")} -
大于 (
>): 检查左边的值是否大于右边的值。如果是,结果为true;否则为false。a := 5b := 3if a > b {fmt.Println("a is greater than b")} -
小于或等于 (
<=): 检查左边的值是否小于或等于右边的值。如果是,结果为true;否则为false。a := 3b := 3if a <= b {fmt.Println("a is less than or equal to b")} -
大于或等于 (
>=): 检查左边的值是否大于或等于右边的值。如果是,结果为true;否则为false。a := 5b := 3if a >= b {fmt.Println("a is greater than or equal to b")}
注意,对于浮点数的比较,由于浮点数在计算机中的表示方式可能导致微小的精度误差,直接使用==来比较两个浮点数是否相等可能不是一个好方法。在这种情况下,可以检查两个浮点数的差的绝对值是否小于某个非常小的阈值。
逻辑运算符
逻辑运算符用于连接或修改布尔表达式(即结果为true或false的表达式)。这些运算符允许你根据一个或多个条件来构建更复杂的逻辑判断。Go语言支持三种基本的逻辑运算符:逻辑与(AND)、逻辑或(OR)和逻辑非(NOT)
1. 逻辑与(AND)&&
逻辑与运算符&&用于连接两个布尔表达式,仅当两个表达式都为true时,整个表达式的结果才为true;否则,结果为false。
a := true | |
b := false | |
if a && b { | |
fmt.Println("Both a and b are true") | |
} else { | |
fmt.Println("At least one of a and b is false") // 这行会被执行 | |
} |
2. 逻辑或(OR)||
逻辑或运算符||用于连接两个布尔表达式,当至少有一个表达式为true时,整个表达式的结果就为true;仅当两个表达式都为false时,结果才为false。
a := true | |
b := false | |
if a || b { | |
fmt.Println("At least one of a and b is true") // 这行会被执行 | |
} else { | |
fmt.Println("Both a and b are false") | |
} |
3. 逻辑非(NOT)!
逻辑非运算符!用于反转布尔表达式的值。如果表达式为true,则!表达式的结果为false;如果表达式为false,则结果为true。
a := true | |
if !a { | |
fmt.Println("a is false") | |
} else { | |
fmt.Println("a is true") // 这行会被执行 | |
} |
注意事项
- 逻辑运算符只能用于布尔表达式。
- 在使用逻辑运算符时,要注意短路行为可能导致的副作用,特别是当表达式的评估具有副作用(如修改变量值)时。
- 逻辑运算符可以组合使用,以构建更复杂的逻辑条件。但是,为了提高代码的可读性,建议使用括号来明确运算符的优先级。
赋值运算符:
赋值运算符是一种用于将值或表达式的结果存储到变量中的基本操作。Go语言中的赋值运算符非常直接和简单,主要是等号(=)用于执行赋值操作。尽管Go语言的赋值运算符相对简单,但它支持多种赋值方式,包括基本的赋值、多重赋值(也称为并行赋值)、以及复合赋值运算符
基本赋值
最基本的赋值形式是将一个值或表达式的结果赋给一个变量。这是通过等号(=)实现的。等号左边是变量名,右边是要赋给该变量的值或表达式。
var a int | |
a = 10 // 将整数10赋值给变量a |
多重赋值(并行赋值)
Go语言支持并行赋值,这允许你一次性给多个变量赋值。这在交换两个变量的值时特别有用,或者在函数返回多个值时接收这些值。
var x, y int | |
x, y = 5, 10 // x被赋值为5,y被赋值为10 | |
// 交换x和y的值 | |
x, y = y, x | |
// 函数返回多个值时的接收 | |
func swap(x, y int) (int, int) { | |
return y, x | |
} | |
a, b := swap(1, 2) // 调用swap函数,并接收其返回的两个值 |
复合赋值运算符
Go语言还支持一系列的复合赋值运算符,这些运算符结合了赋值和算术操作(如加、减、乘、除)或位操作(如按位与、按位或、按位异或)。复合赋值运算符使代码更简洁。
- 加法赋值:
+= - 减法赋值:
-= - 乘法赋值:
*= - 除法赋值:
/= - 取模赋值:
%= - 左移赋值:
<<= - 右移赋值:
>>= - 按位与赋值:
&= - 按位或赋值:
|= - 按位异或赋值:
^=
var a int = 5 | |
a += 3 // 等同于 a = a + 3 | |
a *= 2 // 等同于 a = a * 2 |
注意事项
- 在使用赋值运算符时,必须确保赋值操作的右侧表达式的结果是合法的,并且与左侧变量的类型兼容。
- 在Go语言中,赋值操作会立即执行,并且赋值运算符(
=)本身不返回任何值。 - 多重赋值和复合赋值运算符可以使代码更加简洁和易于阅读,但应注意不要过度使用,以免影响代码的可读性。
其他运算符:
1. 地址运算符 (&)
地址运算符 & 用于获取变量的内存地址。在Go中,每个变量在内存中都有一个地址,通过 & 运算符可以获取这个地址。这个地址是一个指向变量存储位置的指针。
var a int = 10 | |
var ptr *int = &a | |
fmt.Println(ptr) // 输出a变量的内存地址 |
2. 指针运算符 (*)
指针运算符 * 有两种主要用途:
- 当它用于声明指针变量时,表示该变量是一个指针。
- 当它用于指针变量前时,表示访问指针所指向的值。
var ptr *int = &a // ptr是一个指向int的指针 | |
fmt.Println(*ptr) // 输出10,即ptr所指向的值 |
3. 结构体成员访问运算符 (.)
. 运算符用于访问结构体(或映射、切片等复合类型)的成员。当你有一个结构体变量时,可以使用 . 来访问其字段。
type Person struct { | |
Name string | |
Age int | |
} | |
var p Person | |
p.Name = "Alice" | |
p.Age = 30 | |
fmt.Println(p.Name) // 输出Alice |
4. 类型断言运算符 (.(类型))
类型断言用于检查接口变量是否保存了特定类型的值,并获取该值。类型断言的基本语法是 x.(T),其中 x 是接口类型的变量,T 是断言的类型。如果 x 确实保存了 T 类型的值,那么类型断言会返回该值。如果 x 不是 T 类型的,那么类型断言会触发panic,除非使用第二个返回值来检查断言是否成功。
var i interface{} = "hello" | |
s := i.(string) | |
fmt.Println(s) // 输出hello | |
// 安全类型断言 | |
var ok bool | |
s, ok = i.(string) | |
if ok { | |
fmt.Println(s) // 输出hello | |
} else { | |
fmt.Println("断言失败") | |
} |
5. 通道操作运算符 (<-)
通道(channel)是Go语言中的一个核心类型,用于在不同的goroutine之间安全地传递值。<- 运算符在通道操作中扮演了重要角色,它有两种用法:
- 发送操作:
ch <- value,将值发送到通道ch。 - 接收操作:
value := <-ch,从通道ch接收值,并将其赋给变量value。
ch := make(chan int) | |
// 在一个goroutine中发送值 | |
go func() { | |
ch <- 10 | |
}() | |
// 在主goroutine中接收值 | |
value := <-ch | |
fmt.Println(value) // 输出10 |
运算符的优先级
运算符的优先级决定了表达式中各个部分被求值的顺序。。Go语言的运算符优先级遵循了大多数编程语言中广泛接受的规则,但与某些语言(如C或Java)相比,Go的运算符集和关键字可能有所不同,但优先级的基本概念是相似的。
以下是Go语言中运算符的优先级(从高到低)的简要说明:
-
括号 (
(),{},[]):括号用于改变运算的默认顺序。在Go中,大括号{}主要用于控制结构(如if、for、switch等)的块定义,而小括号()和中括号[]则分别用于函数调用、类型断言、索引和切片操作等。 -
一元运算符:
!、^(按位取反,非逻辑非)、+(一元正号)、-(一元负号)、&(地址)、*(指针解引用):这些运算符作用于单个操作数。
-
乘性运算符:
*(乘法)、/(除法)、%(求余):这些运算符执行乘法、除法和取模运算。
-
加性运算符:
+(加法)、-(减法):这些运算符执行加法和减法运算。
-
位移运算符:
<<(左移)、>>(右移):这些运算符用于按位左移和右移操作。
-
比较运算符:
==(等于)、!=(不等于)、<(小于)、<=(小于等于)、>(大于)、>=(大于等于):这些运算符用于比较两个值。
-
逻辑AND运算符:
&&:逻辑AND运算符用于连接两个布尔表达式,仅当两个表达式都为真时,结果才为真。
-
逻辑OR运算符:
||:逻辑OR运算符用于连接两个布尔表达式,只要其中一个表达式为真,结果就为真。
需要注意的是,Go语言中没有逻辑非运算符|||和逻辑AND运算符&&&,也没有C或C++中的位域运算符(如:),且^在Go中作为按位异或运算符,而不是逻辑非运算符(逻辑非在Go中用!表示)。
此外,Go语言中的赋值运算符(如=、+=、-=等)具有较低的优先级,这意味着它们通常是在表达式中最后计算的。
