Go语言入门指南:基础语法和常用特性解析(三) | 青训营

103 阅读3分钟

运算符

位运算

位运算只能用于整数类型的变量,且需当它们拥有等长位模式时。

%b 是用于表示位的格式化标识符。

二元运算符

  • 按位与 &

    对应位置上的值经过和运算结果,并将 T (true) 替换为 1,将 F (false) 替换为 0

      1 & 1 -> 1
      1 & 0 -> 0
      0 & 1 -> 0
      0 & 0 -> 0
    
  • 按位或 |

    对应位置上的值经过或运算结果,并将 T (true) 替换为 1,将 F (false) 替换为 0

      1 | 1 -> 1
      1 | 0 -> 1
      0 | 1 -> 1
      0 | 0 -> 0
    
  • 按位异或 ^

    对应位置上的值根据以下规则组合:

      1 ^ 1 -> 0
      1 ^ 0 -> 1
      0 ^ 1 -> 1
      0 ^ 0 -> 0
    
  • 位清除 &^:将指定位置上的值设置为 0

     package main
     import "fmt"
     func main() {
     	var x uint8 = 15
     	var y uint8 = 4
     	fmt.Printf("%08b\n", x &^ y);  // 00001011
     }
    

一元运算符

  • 按位补足 ^

    该运算符与异或运算符一同使用,即 m^x,对于无符号 x 使用 “全部位设置为 1” 的规则,对于有符号 x 时使用 m=-1。例如:

      ^10 = -01 ^ 10 = -11
    
  • 位左移 <<

    • 用法:bitP << n

    • bitP 的位向左移动 n 位,右侧空白部分使用 0 填充;如果 n 等于 2,则结果是 2 的相应倍数,即 2 的 n 次方。例如:

        1 << 10 // 等于 1 KB
        1 << 20 // 等于 1 MB
        1 << 30 // 等于 1 GB
      
  • 位右移 >>

    • 用法:bitP >> n
    • bitP 的位向右移动 n 位,左侧空白部分使用 0 填充;如果 n 等于 2,则结果是当前值除以 2 的 n 次方。

当希望把结果赋值给第一个操作数时,可以简写为 a <<= 2 或者 b ^= a & 0xffffffff

位左移常见实现存储单位的用例

使用位左移与 iota 计数配合可优雅地实现存储单位的常量枚举:

type ByteSize float64
const (
	_ = iota // 通过赋值给空白标识符来忽略值
	KB ByteSize = 1<<(10*iota)
	MB
	GB
	TB
	PB
	EB
	ZB
	YB
)

在通讯中使用位左移表示标识的用例

type BitFlag int
const (
	Active BitFlag = 1 << iota // 1 << 0 == 1
	Send // 1 << 1 == 2
	Receive // 1 << 2 == 4
)

flag := Active | Send // == 3

逻辑运算符

Go 中拥有以下逻辑运算符:==!=(第 4.5.1 节)、<<=>>=

它们之所以被称为逻辑运算符是因为它们的运算结果总是为布尔值。例如:

b3 := 10 > 5 // b3 is true

算术运算符

常见可用于整数和浮点数的二元运算符有 +-* 和 /

(相对于一般规则而言,Go 在进行字符串拼接时允许使用对运算符 + 的重载,但 Go 本身不允许开发者进行自定义的运算符重载)。

对于整数运算而言,结果依旧为整数,例如:9 / 4 -> 2

取余运算符只能作用于整数:9 % 4 -> 1

整数除以 0 可能导致程序崩溃,将会导致运行时的恐慌状态(如果除以 0 的行为在编译时就能被捕捉到,则会引发编译错误)。

浮点数除以 0.0 会返回一个无穷尽的结果,使用 +Inf 表示。

你可以将语句 b = b + a 简写为 b += a,同样的写法也可用于 -=*=/=%=

对于整数和浮点数,你可以使用一元运算符 ++(递增)和 --(递减),但只能用于后缀:

i++ -> i += 1 -> i = i + 1
i-- -> i -= 1 -> i = i - 1

同时,带有 ++ 和 -- 的只能作为语句,而非表达式,因此 n = i++ 这种写法是无效的,其它像 f(i++) 或者 a[i]=b[i++] 这些可以用于 C、C++ 和 Java 中的写法在 Go 中也是不允许的。

在运算时 溢出 不会产生错误,Go 会简单地将超出位数抛弃。如果你需要范围无限大的整数或者有理数(意味着只被限制于计算机内存),可以使用标准库中的 big 包,该包提供了类似 big.Int 和 big.Rat 这样的类型。

运算符与优先级

有些运算符拥有较高的优先级,二元运算符的运算方向均是从左至右。下表列出了所有运算符以及它们的优先级,由上至下代表优先级由高到低:

优先级 	运算符
 7 		^ !
 6 		* / % << >> & &^
 5 		+ - | ^
 4 		== != < <= >= >
 3 		<-
 2 		&&
 1 		||