运算符介绍
运算符用于在程序运行时执行数学或逻辑运算,Go 语言内置的运算符有:
- 一元运算符
+
一元加法-
负数
-
二元运算符
-
算术运算符
-
位运算符
-
逻辑运算符
-
比较运算符
-
Go语言中所有的二元运算符共有五种优先级,如下所示,它们按照优先级递减的顺序的排列:
优先级 | 运算符 |
---|---|
5 | * / % << >> & &^ |
4 | + – | ^ |
3 | == != < <= > >= |
2 | && |
1 | || |
在同一个优先级,使用左优先结合规则,但是使用括号可以提升优先级,所以建议使用括号明确优先顺序。
一、 一元运算符
一元的加法和减法运算符 | 描述 |
---|---|
+ | 一元加法 (无效果) |
– | 负数 |
对于整数、浮点数和复数,+x就是x,-x则是x 的负数。例如+(-8)得-8
一元指针运算符 | 描述 | 实例 |
---|---|---|
& | 返回变量存储地址 | &a; 将给出变量的实际地址。 |
* | 指针变量。 | *a; 是一个指针变量 |
二、 二元运算符
2.1 二元运算的重要原则
重申我们之前学过的一个重要原则,如下所示
- go是强类型语言,运算必须是同类型之间进行,即便涉及到无类型的量(假设为x)go也会将其先隐式转换成相同的类型才能进行后运,而转换是否合法,判断的依据是显式转换T(x)是否合法,因为底层发生的就是隐式的T(x)转换。
除了位运算之外,二元运算中的算数运算、赋值运算、比较运算符涉及到多个量进行运算,必须遵循上述规则。
2.2 算数运算符
运算符 | 描述 |
---|---|
+ | 相加 |
– | 相减 |
* | 相乘 |
/ | 相除 |
% | 求余/取模 |
注意:
-
1、算术运算符+、-、
*
和/
可以在整数、浮点数和复数的字面值之间混用,但是取模运算符%仅用于整数间的运算fmt.Println(3 % 2) // 1 fmt.Println(3.1 % 2) // 报错:operator % not defined on untyped float
-
2、在Go语言中,%取模运算符的符号和被取模数的符号总是一致的,因此
-5%3
和-5%-3
结果都是-2。// 可以这做 -(-5 % -3)
-
3、除法运算符
/
的行为则依赖于操作数是否为全为整数,例如fmt.Println(8.0 / 5.0) // 结果为1.6 fmt.Println(8 / 5.0) // 结果为1.6 fmt.Println(8.0 / 5) // 结果为1.6 fmt.Println(8 / 5) // 结果为1,因为整数除法会向着0方向截断余数。
-
4、因为除法运算符/会根据操作数的类型生成对应类型的结果,所以不同写法的常量除法表达式可能对应不同的结果:
var f float64 = 212 fmt.Println((f - 32) * 5 / 9) // "100"; (f - 32) * 5 得到的是浮点型 fmt.Println(5 / 9 * (f - 32)) // "0"; 5/9 得到的是整型 fmt.Println(5.0 / 9.0 * (f - 32)) // "100"; 5.0/9.0 得到的是浮点型
-
5、针对一个算术运算的结果,不管是有符号还是无符号的,如果需要更多的bit位才能正确表示的话,就说明计算结果是溢出了,而超出的高位的bit位部分将被丢弃,也就是说如果原始的数值是有符号类型,而且最左边的bit为是1的话,那么最终结果就可能是负的,例如int8的例子:
var u uint8 = 255 fmt.Println(u, u+1, u*u) // "255 0 1" var i int8 = 127 fmt.Println(i, i+1, i*i) // "127 -128 1"
???为何出现128呢,egon来先扫一下盲,估计会扫死99%的人
问:8位二进制数可以表示的数值范围是多少,99%的人张口就来:-128~127 ok,8位二进制数,最高位需要用来表示符号,那么剩下的7位用来表示数值 于是,最大数为1111 1111=>+127,最小0111 1111=>-127,卧槽,得出的结论是8位二进制数可以表示的数值范围是-127到+127,傻逼了吧你,哈哈哈 灵魂拷问:-128到底怎么来的??? 真相是这样的: 8位二进制数用7位表示数值,那么7位2进制数000 0000的值为0 那么,它前面加上符号位0,还表示0吧? 那好,如果它前面加上1呢,仍然表示0?这不是重复了么? 一个0,怎么用两个值来表示呢!!! 所以1000 0000就表示-128啦,
-
6、字符串也可以使用+运算符
其中+操作符将两个字符串链接构造一个新字符串:
fmt.Println("goodbye" + s[5:]) // "goodbye, world"
字符串的值是不可变的:一个字符串包含的字节序列永远不会被改变,当然我们也可以给一个字符串变量分配一个新字符串值。可以像下面这样将一个字符串追加到另一个字符串:
s := "left foot" t := s s += ", right foot"
这并不会导致原始的字符串值被改变,但是变量s将因为+=语句持有一个新的字符串值,但是t依然是包含原先的字符串值。
fmt.Println(s) // "left foot, right foot" fmt.Println(t) // "left foot"
2.3 位运算符
位运算符对整数在内存中的二进制位进行操作(详解附录:位运算)
运算符 | 描述 | 实例 |
---|---|---|
<< | 左移,左移n位就是乘以2的n次方。 “a<<b”是把a的各二进位全部左移b位,高位丢弃,低位补0。 | A << 2 结果为 240 ,二进制为 1111 0000 |
>> | 右移,右移n位就是除以2的n次方。 “a>>b”是把a的各二进位全部右移b位。 | A >> 2 结果为 15 ,二进制为 0000 1111 |
& | 位运算AND,参与运算的两数各对应的二进位相与。 (两位均为1才为1) | (A & B) 结果为 12, 二进制为 0000 1100 |
| | 位运算OR,参与运算的两数各对应的二进位相或。 (两位有一个为1就为1) | (A | B) 结果为 61, 二进制为 0011 1101 |
^ | 位运算XOR,参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。 (两位不一样则为1) | (A ^ B) 结果为 49, 二进制为 0011 0001 |
&^ | 位清空 (AND NOT) |
注意:n次方运算不是^,而是math.Pow(),如下所示
var aaa = math.Pow(10,38) // 10的38次方
fmt.Printf("%T,%v\n",aaa,aaa) // float64,1e+38
2.4 赋值运算符
对于算数运算符和位运算符,还结合赋值符号书写成简化的赋值语句,例如+运算符还有一个与赋值相结合的对应运算符+=
运算符 | 描述 |
---|---|
= | 简单的赋值运算符,将一个表达式的值赋给一个左值 |
+= | 相加后再赋值 |
-= | 相减后再赋值 |
*= | 相乘后再赋值 |
/= | 相除后再赋值 |
%= | 求余后再赋值 |
<<= | 左移后赋值 |
>>= | 右移后赋值 |
&= | 按位与后赋值 |
|= | 按位或后赋值 |
^= | 按位异或后赋值 |
注意1:
在Go语法中,变量初始化和变量赋值是两个不同的概念。下面为声明一个变量之后的赋值
过程:
var v int
v = 123
Go语言的变量赋值与多数语言一致,但Go语言中提供了C/C++程序员期盼多年的多重赋值功
能,比如下面这个交换i和j变量的语句:
i, j = j, i
// 在不支持多重赋值的语言中,交互两个变量的内容需要引入一个中间变量:
t = i; i = j; j = t;
多重赋值的特性在Go语言库的实现中也被使用得相当充分,在介绍函数的多重返回值时,
将对其进行更加深入的介绍。总而言之,多重赋值功能让Go语言与C/C++语言相比可以非常明显
地减少代码行数。多重赋值细节和原理参照官方文档golang官网:https://golang.org/ref/spec#Constants
注意2:
再次重申,go是强类型,但凡涉及到两个变量的操作,必须是同类型之间才行,因为相同的类型底层的内存数据结构才一样。赋值操作就涉及到了两个变量
var x [3]int = [3]int{11,22,33}
var y [2]int = [2]int{11,22}
x = y // 错误
注意3:
:=要求等号左边必须至少有一个新变量
而匿名变量_不是新变量,所以当左边只有一个_时会报错
_="egon" // 这个是ok的,因为是赋值操作
_:="egon" // 这个就不行
注意4: 数值变量也可以支持++
递增和--
递减语句(译注:自增和自减是语句,而不是表达式或运算符,因此x = i++
之类的表达式是错误的。语句只是执行指令,表达式是在执行计算会有返回值):
x:=123
y:=-3.1
x-- // 等价于 x = x - 1;x 变成 122
y++ // 等级于 y = y + 1;y 变成 -2.1
fmt.Println(x) // 122
fmt.Println(y) // -2.1
2.5 比较运算符
比较表达式的结果是布尔类型
运算符 | 描述 |
---|---|
== | 检查两个值是否相等,如果相等返回 True 否则返回 False。 |
!= | 检查两个值是否不相等,如果不相等返回 True 否则返回 False。 |
> | 检查左边值是否大于右边值,如果是返回 True 否则返回 False。 |
>= | 检查左边值是否大于等于右边值,如果是返回 True 否则返回 False。 |
< | 检查左边值是否小于右边值,如果是返回 True 否则返回 False。 |
<= | 检查左边值是否小于等于右边值,如果是返回 True 否则返回 False。 |
!!!!!!注意!!!!!!
-
1、相等性判断我们将在随后详细介绍每种数据类型时详细介绍
-
2、通常只有同类型的数字之间、或者与数字字面量才可以比大小,比较特殊的是:字符串是可以比大小,会按次序比较字节,而不是字符,这一点我们将在字符串章节详细介绍;
2.6 逻辑运算符
运算符 | 描述 |
---|---|
&& | 逻辑 AND 运算符。 如果两边的操作数都是 True,则为 True,否则为 False。 |
|| | 逻辑 OR 运算符。 如果两边的操作数有一个 True,则为 True,否则为 False。 |
! | 逻辑 NOT 运算符。 如果条件为 True,则为 False,否则为 True。 |
!、&&、||
优先级! > && > ||,推荐用()来提升优先级
连接多个条件时有短路行为