Go 程式設計教學:運算子 (Operator)

PUBLISHED ON SEP 10, 2017 — PROGRAMMING

在上一篇文章中,我們介紹了 Go 的變數和資料型別。接著,在本篇文章中,我們會介紹運算子 (operator),運算子如同程式中的基本指令,不同的資料型別可用的運算子各自不同;透過這些基本指令,可以組合出更複雜的功能。

Go 包含以下運算子:

  • 代數運算子 (arithmetic operator)
  • 二元運算子 (bitwise operator)
  • 關係運算子 (relational operator)
  • 邏輯運算子 (logical operator)
  • 位址運算子 (adress operator)
  • 接收運算子 (receive operator)

我們將在本文中逐一介紹這些操作子。

代數運算子

十進位數字的可用的運算子,就是基本的代數運算,相信大家都已經相當熟悉。Go 的代數運算子如下:

  • a + b:相加
  • a - b:相減
  • a * b:相乘
  • a / b:相除
  • a % b:取餘數

實例如下:

package main

func main() {
	a := 3
	b := 2

	assert(a+b == 5, "It should be 5")
	assert(a-b == 1, "It should be 1")
	assert(a*b == 6, "It should be 6")
	assert(a/b == 1, "It should be 1")
	assert(a%b == 1, "It should be 1")
}

// Home-made `assert` for Go.
func assert(condition bool, msg string) {
	if !condition {
		panic(msg)
	}
}

在本例中,我們用自製的 assert 語句取代常見的 fmt.Println,因為前者可以從程式碼中直接看出我們的意圖。當程式可順利執行時,代表程式沒有錯誤。

浮點數沒有取餘數運算,其他運算和整數相同。另外,在 Go 裡面,除以零會引發程式錯誤,程式設計者需自行檢查及預防。

二元運算子

二元運算使用二進位數進行運算,有以下數種運算方式:

  • a & b:bitwise AND,兩者皆為 1 時才為 1
  • a | b:bitwise OR,兩者其中之一為 1 時即為 1
  • a ^ b:bitwise XOR,兩者僅其一為 1 時才為 1
  • a << n:左移
  • a >> n:右移

以下例子用二元運算模擬系統權限:

package main

const EXEC = 1  // 0001
const WRITE = 2 // 0010
const READ = 4  // 0100

func main() {
	// Read only
	assert(READ == 4, "It should be read-only")

	// Read and write
	assert(READ^WRITE == 6, "It should be both readable and writable")

	// Read and Exec
	assert(READ^EXEC == 5, "It should be both readable and executable")
}

// Home-made `assert` for Go.
func assert(condition bool, msg string) {
	if !condition {
		panic(msg)
	}
}

二元運算多用於低階程式 (low-level programming),一般情境下較少常用到。雖然 Go 不是真正的系統程式設計 (system programming) 語言,仍保留這項特性。

關係運算子

關係運算子是用來比較兩個值之間的大小,Go 有以下關係運算子:

  • a == b:相等
  • a != b:不等
  • a < b:小於
  • a <= b:小於或等於
  • a > b:大於
  • a >= b:大於或等於

基本上,Go 內建型態都可以相互比較。關係運算子會回傳布林值,主要是用在條件判斷中,我們將於後文介紹條件判斷。

package main

func main() {
	a := 5
	b := 3

	assert((a == b) == false, "It should be false")
	assert((a != b) == true, "It should be true")
	assert((a > b) == true, "It should be true")
	assert((a >= b) == true, "It should be true")
	assert((a < b) == false, "It should be false")
	assert((a <= b) == false, "It should be false")
}

// Home-made `assert` for Go.
func assert(condition bool, msg string) {
	if !condition {
		panic(msg)
	}
}

邏輯運算子

邏輯運算子用來結合數個條件判斷,以達成複合的效果。Go 有以下邏輯運算子:

  • &&:且 (AND)
  • ||:或 (OR)
  • !:否 (NOT)

一般程式設計書籍會提供真值表 (true value table),但其實不需要記憶那個表格,只要記得:

  • AND (&&):兩者為真為真
  • OR (||):其中之一為真為真
  • NOT (!):真變偽,偽變真

以下為實例:

package main

func main() {
	// and
	assert((true && true) == true, "It should be true")
	assert((true && false) == false, "It should be false")
	assert((false && true) == false, "It should be false")
	assert((false && false) == false, "It should be false")

	// or
	assert((true || true) == true, "It should be true")
	assert((true || false) == true, "It should be true")
	assert((false || true) == true, "It should be true")
	assert((false || false) == false, "It should be false")

	// not
	assert((!true) == false, "It should be false")
	assert((!false) == true, "It should be true")
}

// Home-made `assert` for Go.
func assert(condition bool, msg string) {
	if !condition {
		panic(msg)
	}
}

邏輯運算子會回傳布林值,同樣也是用於條件判斷中。

位址運算子

位址運算子牽涉到指標 (pointer),接收運算子牽涉到通道 (channel),這都是比較進階的概念,我們將於後文介紹。

運算子優先順序

不同運算子放在一起時,有一套內定的順序 (precedence),如下:

Precedence    Operator
5             *  /  %  <<  >>  &  &^
4             +  -  |  ^
3             ==  !=  <  <=  >  >=
2             &&
1             ||

但是,不要記這個順序,因為:

  • 代數運算和數學上的運算先後順序相同
  • 撰寫較簡單的敘述,就可避免過於複雜的優先順序
  • 可以用括號改變優先順序,同時可讓程式碼更清晰

經過本文的說明,相信讀者對運算子已經有相當的概念,日後可用在自己的程式中。在下一篇文章中,我們會介紹控制結構 (control structures),包括條件敘述 (condition) 和迴圈 (loop)。

comments powered by Disqus