Go基础-008 运算符

1.概述

用于完成特定运算语法标识。例如 + - * /等。
基于不同的功能,分成很多类:

  • 算术运算
  • 关系运算
  • 逻辑运算
  • 位运算
  • 赋值运算

2.算术运算

+ - * / % ++ --
针对的是数值类型,其中%取余操作仅仅针对于整型。

v++ 相当于 v=v+1
v-- 相当于 v=v–1

v := 10
v ++ 
fmt.Println(v) // 11

注意:

  • 不支持,v ++ 参与直接运算,也就是 v = v + v++,将 v++直接作为值去参与运算是
    不被允许的。因为 v++ 作为语句看待,而不是作为表达式看待。
  • + 还支持字符串的连接。

3.关系运算

关系,用于衡量两个数据是否满足某个特定的逻辑关系的运算符。满足关系返回真 true,
不满足关系返回家 false。(关系运算符永远返回布尔数据)
关系运算符如下表:


注意:

  • 返回的永远是布尔型数据。
  • 不是全部的数据类型,都支持以上的运算符。
  • 参与比较的运算符类型需要一致。(字符串和int 不能比)
  • 字符串类型的比较,基于每个字节的码值做比较,第一个不同的字节确定大小。(与长度等其他因素无关)

代码演示:

fmt.Println(10 > 8) // true 
fmt.Println(10 > 20) // false 
fmt.Println(10. > 8.5) // true
fmt.Println(10.1 < 20) // true

//fmt.Println(true > false) // 不能比较大小关系
fmt.Println(true == false) // 可以比较是否相等 false

fmt.Println("abc" > "abd") // false
fmt.Println("abc" > "abb") // true
fmt.Println("abc" > "b") // false 
fmt.Println("abc" > "") // true 
fmt.Println("abc" > "ab") // true 
fmt.Println("abc" > "100") // true 
fmt.Println("abc" > "ABC") // true
fmt.Println([3]int{1} == [3]int{2}) // false

4.逻辑运算

用于计算多个条件间组合逻辑关系的运算符。参与运算的运算数为可以得到布尔值的表
达式,运算结果为布尔值。
支持的逻辑运算符:


代码演示:

fmt.Println(false || false) // false
fmt.Println(true && false) // false
fmt.Println(!(false || false))  // true
fmt.Println(false || (true || false && true)) //  true

4.赋值运算

等号,完成赋值。
赋值运算符还可以配合一些二元运算符,完成自赋值运算。等号左边称之为左值,右边称之 为右值。右值需要是一个表达式,左值是一个变量。
(二元运算符,有 2 个运算符参与运算的符号,例如加减乘除)

运算符列表:



自赋值:

v := 42
v+=10 相当于 v=v+10 
v = 52

批量操作:

v1, v2, v3 := 1, 2, 3
v1, v2, v3 = 4, 5, 6 

批量赋值,是依次计算右值表达式的值,完毕后再 为左值变量赋值。

代码演示:

//赋值
v := 10
v1, v2, v3 := v, v+10, v+20 
fmt.Println(v1, v2, v3) // 10 20 30

// 注意 :是全算完后再赋值
v1, v2, v3 = 5, v1 + 10, v2 + 10 
fmt.Println(v1, v2, v3) //  5 20 30  

// 过程 5, 10+10, 20+10
// 过程 v1=5, v2=20, v3=30

5. 位算符

1)规则

位,bit,运算的最基本单位。 每个位只有 0 或 1 两种可能性。

支持的运算符与逻辑运算符类似,&, |, ^, &^, <<, >>。
逻辑运算是对布尔值 true 或 false 的 运算,而位运算是对数字 0,1 的运算,值都是只有两种可能性。
位运算是针对于每个位都参与运算。参与运算的数据要求是整数,由于一个整数会占用多个 位(8,16, 32, 64),因此,每次位运算都会计算多次。
例如,两个 int32 进行位运算, 就需要计算 32 次,每个位都要计算一次。12 & 24 就需要计算 32 次,假设两个数都是 int32 类型。

支持的运算符:


说明:

  • 移位
    13>>2,右移 2 位
    13<<3,左移 3 位


  • &^ 位与非


使用整数(正整数)运算时,将正整数转为二进制,逐位进行运算。
代码演示:

v3 := 13
v4 := 9 fmt.Println(v3 & v4) 
//13 00001101
//9   00001001
// &
// = 00001001

fmt.Println(v3 | v4) 
// //13 00001101
// //9   00001001
// // |
// // = 00001101

fmt.Println(v3 ^ v4) 
//13 00001101
//9 00001001
// ^
// = 00000100 4

fmt.Println(13 >> 2, 13 << 3)

fmt.Println(13 &^ 9)
//13 00001101
//9 00001001
//&^
// = 00000100 4
2) 错误级别配置例子
① 说明

通常用于管理一组相关的开关状态。
开关状态,值得是 0 或 1。
(实操中很常用的例子)例如,需要一个日志系统,管理日志级别,有信息,调试,警 告,错误,致命错误,不推荐。增加一个系统配置,用于设置当前系统所使用的日志级别。 意味着,我们可以选择记录信息和错误级别的日志,或者记录调试和不推荐基本的日志。

需要做到:

  • 记录当前启用的级别
  • 判断某种级别是否启用
  • 开启某个特定级别(在不影响其他级别的基础上)
  • 关闭某个特定级别(不影响其他级别)
  • 翻转某个级别。
② 记录配置

本案例中,就涉及一组开关状态。
适合使用一个整数的每个位,对应表示某个级别,使用该整数记录整体的配置,基于位运算 完成业务逻辑。
设计如图:


本例中,仅仅需要一个整型即可记录当前的配置状态。 利用位运算,完成业务逻辑:

// 配置项,当前日志级别 
setting := 13 // 00001101
③ 构建一组级别数据

级别数据的特征,对应的位为 1,其他位都是 0
可以利用 常量的 iota 来实现:

const (
  levelInfo = 1 << iota // 00000001 << 0 = 00000001 
  levelDebug // 1 << iota 00000001 << 1 = 00000010 2 
  levelWaning // 00000100 4
  levelError // 00001000 8
  levelFatal // 00010000 16
)
④ 判断某种基本是否启用

语法上,就是判断某个位是否为 1。
思路: 构建一个只有对应位为 1,其他位为 0 的数值。例如需要判断 error 基本是否启 用,则构建一个 error 对应的位为 1,其他位为 0 的数据。例如:00001000。

利用该数据,与当前配置值,做位与运算,如果结果为 > 0(error 对应数据) ,表示 对应为设置为 0,结果为==0 表示,对应位设置为 0.

13 00001101 与 00001000 做位与运算,过程:
00001101 &
00001000
00001000

代码演示:

// 配置项,当前日志级别 setting := 13 // 00001101

// 判断 Info 级别是否启用
fmt.Println(setting & levelInfo > 0) // true 
// 判断 debug 级别是否启用
fmt.Println(setting & levelDebug > 0) // false 
// 判断 warnig 级别是否启用
fmt.Println(setting & levelWaning > 0) // true 
// 判断 warning 级别是否启用
fmt.Println(setting & levelError > 0) // true 
// 判断 fatal 级别是否启用
fmt.Println(setting & levelFatal > 0) // false

⑤ 开启某个级别

语法上,将某个为设置为 1,不能影响其他位。
某个为之前可能是 1 或 0,最终的结果都要是 1.
实现思路:位或上,对应位为 1 的值即可。 演示:

// 开启

// 设置 debug 级别为开启
fmt.Println(setting & levelDebug > 0) // false 
//setting = setting | levelDebug
setting |= levelDebug
fmt.Println(setting & levelDebug > 0) // true

// 设置 error 级别为开启
fmt.Println(setting & levelError > 0) // true 
setting |= levelError
fmt.Println(setting & levelError > 0) // true
⑥ 关闭某个级别

语法上,将某个位设置为 0。无论原来是什么。
实现:与对应的位为 1 的数据,做&^运算即可。

代码演示:

// 关闭

// 关闭 error 级别
fmt.Println(setting & levelError > 0) // true 
setting &^= levelError
fmt.Println(setting & levelError > 0) // false

// 关闭 fatal 级别
fmt.Println(setting & levelFatal > 0) // false 
setting &^= levelFatal
fmt.Println(setting & levelFatal > 0) // false
⑦ 反转状态

原来为 1,设置为 0,原来为 0 设置为 1.
实现:对某位为 1 的值,进行位异或运算即可。

6.优先级别和结合顺序

运算符优先级: 当表达式由多个运算符构成时,计算的顺序有先后。
结合顺序: 当级别一致时,选择从左至右或者反过来,称之为结合顺序。

类似四则混合运算规律: 从左至右运算,先乘除后加减,先算括号里边的。

运算符的优先级为,由上至下,由高到低:


注意:推荐使用括号,干预优先级别,让运算顺序使用括号变得清晰明了!

7.其他

... 剩余/展开,数组长度占位
<- 信道写入读取

8.表达式和语句

1)表达式

表达式,expression,可以当做值使用的语法,可以计算得到值的语法,称之为表达式。可以使用表达式为变量赋值,直接输出,作为函数的返回值,或者参数进行传递都可以。
典型的表达式:

  • 数据的字面量, 42 false
  • 变量, v
  • 表达式参与运算 42 + 1024
  • 返回值函数调用, len(array)
2)语句

语句, statement,完成特定功能的语法,被视作一个独立的整体,没有后续值可用。例如 if, switch。语句不能直接参与表达式运算,需要独立执行。
典型的语句:

  • if
  • switch
  • for
  • ++、--

你可能感兴趣的:(Go基础-008 运算符)