10 运算符

运算符介绍

运算符用于在程序运行时执行数学或逻辑运算,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。

!、&&、||

优先级! > && > ||,推荐用()来提升优先级
连接多个条件时有短路行为
上一篇
下一篇
Copyright © 2022 Egon的技术星球 egonlin.com 版权所有 帮助IT小伙伴学到真正的技术