重學Go語言 | 運算子與控制結構

語言: CN / TW / HK

我正在參加「掘金·啟航計劃」

對於任何程式語言來說,運算子和控制結構都算是最基礎的知識了,既然是基礎,當然非常有必要學習,因此在這篇文章中我們就來討論一下。

運算子

運算子的作用是將運算元組合成表示式,比如下面的程式碼中,我們通過賦值和加號組成了兩個表示式:

var i,j = 1,2 n := i + j

Go的運算子大體分為六種:算術運算子關係運算符邏輯運算子位運算子賦值運算子指標運算子

算術運算子

| 運算子 | 含義 | | ------ | ---------------------------------------------------------- | | + | 加號,除了用於整數,浮點數,複數外,還可以用於字串的拼接 | | - | 減號 | | * | 相乘 | | / | 相除 | | % | 求餘,只能用於整數 | | ++ | 自增 | | -- | 自減 | | + | 正數,注意與加號(+)的區別 | | - | 負數,注意與減號(-)的區別 |

用法示例:

``` var str1 string = "hello" var str2 string = "world" str := str1 + str2 //使用+號拼接字串

i := 3.2 % 2 //報錯,只能對整數求餘

var n int = 1 n++ ++n //錯誤,自增只能加了運算元後面,自減也是同樣的 ```

關係運算符

通過邏輯運算子組成的表示式,其計算結果為布林值,一般用於控制結構的條件部分:

| 運算子 | 含義 | | ------ | ---------- | | == | 相等 | | != | 不相等 | | <= | 小於或等於 | | < | 小於 | | >= | 大於或等於 | | > | 大於 |

用法示例:

if 2 == (1 + 1) { fmt.Println("相等") }

邏輯運算子

邏輯運算子組成的表示式,其計算結果也同樣蠅布林值,因此也用於控制結構的條件部分:

| 運算子 | 含義 | | ------ | ------------------------------------ | | && | 邏輯與 | | \|\| | 邏輯或 | | ! | 邏輯非,一元運算子,具有較高的優先順序 |

位運算子

位運算子只能用於整數

| 運算子 | 含義 | | ------ | -------------------------------------------------------- | | & | 按位與,兩個運算元都1的位置為1,否為0 | | \| | 按位或,兩個運算元只要有1的位置,都為1,否則為0 | | ^ | 按位異或,兩個運算元都相同為0,否則為1 | | << | 按位左移 | | >> | 按位右移 | | &^ | 按位清空,根據右邊運算元為1的位置,將左邊對應位置設為0。 |

用法示例:

``` fmt.Println(2 & 1) // 00000010 & 00000001,可以看出,沒有哪個位置兩個操作都為1,因此結果為:00000000 fmt.Println(2 | 1) // 00000010 & 00000001,結果為00000011,也就是3 fmt.Println(2 ^ 1) // 00000010 & 00000001,結果為00000011,也就是3

fmt.Println(1 << 1) //00000001 => 00000010 fmt.Println(2 >> 1) //00000010 => 00000001

fmt.Println(23 &^ 5) 00010111 &^ 00000101 => 00010010 ```

賦值運算子

| 運算子 | 含義 | | ------ | ------------------------------------------------------------ | | = := | 賦值 | | += | 先將左側與右側的運算元相加,再賦值給左邊的變數 | | -= | 先將左側與右側的運算元相減,再賦值給左邊的變數 | | *= | 先將左側與右側的運算元相乘,再賦值給左邊的變數 | | /= | 先將左側與右側的運算元相除,再賦值給左邊的變數 | | %= | 先將左側與右側的運算元求餘,再賦值給左邊的變數 | | <<= | 先將左側的運算元按右側的運算元向左位移,再將位移結果賦給左邊的變數 | | >>= | 先將左側的運算元按右側的運算元向右位移,再將位移結果賦給左邊的變數 | | &= | 先將左側與右側的運算元進行按位與計算,再將計算結果賦給左邊的變數 | | != | 先將左側與右側的運算元進行按位或計算,再將計算結果賦給左邊的變數 | | ^= | 先將左側與右側的運算元進行按異或計算,再將計算結果賦給左邊的變數 |

指標運算子

| 運算子 | 含義 | | ------ | ---------------------- | | & | 獲取變數在記憶體中的地址 | | * | 宣告指標變數 |

運算子的優先順序

Go的++與--運算子作用於運算元時形成的是表示式,因此不納入運算子的優先順序中。

在Go語言中,一元運算子具有更高的優先順序,如+(正數)-(負數)!(取反)*(指標宣告)&(取址)

而賦值運算子的優先順序最低,除了一元運算子以及賦值運算子外,剩下的運算子可以劃分為五個優先等級:

| 優先順序 | 運算子 | | ------ | --------------------------- | | 5 | * / % << >> & &^ | | 4 | + - \| ^ | | 3 | == != < <= >= > | | 2 | && | | 1 | \|\| |

控制結構

Go的控制結構包括if語句、for語句和switch語句三種。

If

if語句用於判斷某個條件是否滿足,如果滿足,則執行if語句中的程式碼塊,如果不滿足,則忽略if語句中的程式碼塊並繼續向後執行。

最簡單的if語句結構為:

if boolean expression { // do something }

其中boolean expression為一個可以得到布林值的表示式,當布林值為true,會執行if語句中的程式碼塊,如:

if 2 < 10 { fmt.Println("ok") }

除了用於判斷的boolean expression外,if也可以包含一個初始化表示式:

if initialization;boolean expression{ // do something }

這種情況下,if會先執行初始化表示式,之後再判斷boolean expression得到的布林是否為true

if i = 10;i < 100 { fmt.Println("ok") }

if語句後面也可以跟上else語句,當然if條件不滿足時,會執行else語句中的程式碼塊:

if boolean expression{ // do something }else{ // do something }

用法示例:

if i = 11;i < 11{ fmt.Println("ok") }else{ fmt.Println("bad") }

如果有多個分支條件判斷,可以在if語句後面跟上多個else if 語句,最後可以跟上else語句,當所有條件都不滿足時,會執行else語句中的程式碼塊:

if boolean expression1 { // do something } else if boolean expression2 { // do something else } else if boolean expression3 { // do something else }else { // catch-all or default }

For

for語句用於根據條件迴圈執行其中的程式碼塊,最簡單的for語句格式如下:

for condition { //do something }

condition為一個可得到布林值的表示式,Go語言中並沒有while或者do-while語句,因此這種方式的用法接近其他程式語言的while或者do-while語句:

x := 1 for x < 20{ fmt.Println(x) x++ }

如果condition為空,那麼此時for則為死迴圈:

for { //do something }

for最經典,在其他程式語言也有的用法是下面這種形式:

for init statement;condition;post statement{ //do something }

用法示例:

for i := 0; i< 10 ;i++ { fmt.Println(i) }

另外,for語句還與關鍵字range配合,可以用於遍歷陣列、map和切片等,其作用類似PHP中的foreach語句:

for k,v := range array { //do something }

用法示例:

``` var a [10]int = [10]int{1,2,3,4,5,6,7,8,9,10}

for index,value := range a { fmt.Println(index,value) } ```

使用break關鍵字結束迴圈

for i := 0; i < 10; i++ { if i == 5 { break } fmt.Println(i) }

使用continue結束跳過單次迴圈:

for i := 0;i<10;i++{ if i == 5 { continue } fmt.Println(i) }

Switch

Switch與if類似,用於根據條件執行滿足條件的程式碼塊,但其用法與if不同,switch有幾種不同的用法:

第一種使用方法會將switch後面的值與case後面所跟的值進行比較,滿足條件則執行case中的程式碼塊,如果都不滿足,則執行default中的程式碼塊,其結構如下所示:

switch var1 { case val1: ... case val2: ... default: ... }

用法示例:

var x = 8 switch x { case 8 : fmt.Println("8") case 9 : fmt.Println("9") case 10 : fmt.Println("10") default : fmt.Println("not found") }

從上面的例子可以看出,在滿足某個條件後,switch執行完該分支就會退出switch語句,不需要像其他程式語言一樣使用break來退出switch語句。

如果不想退出switch語句,需要繼續讓switch語句往下執行,可以在case語句內使用fallthrough關鍵詞:

var x = 8 switch x { case 8 : fmt.Println("8") fallthrough case 9 : fmt.Println("9") fallthrough case 10 : fmt.Println("10") default : fmt.Println("not found") }

上面語句在匹配到case 8:之後,碰到了fallthrough語句,所以繼續往下執行,接著繼續碰到fallthrough語句,再繼續執行,因此三個case程式碼塊都會被執行。

switch的另一種用法是將後面的變數省略,而把執行的判斷條件放在case關鍵詞後面,這個用法與if/elseif語句類似:

switch { case condition1: ... case condition2: ... default: ... }

用法示例:

x := 10 switch { case x >= 10: fmt.Println("10") case x > 11: fmt.Println("11") default: fmt.Println("not found") }

switch後面可以跟上一個初始化語句:

switch initialization { case condition1: ... case condition2: ... default: ... }

用法示例:

switch x := 10; { case x >= 10: fmt.Println("10") case x > 11: fmt.Println("11") default: fmt.Println("not found") }

type-switchswitch語句的另一種用法,主要用於型別斷言,後續在學習介面(interface)再介紹

小結

總結一下,這篇文章主要講了三點:

  1. Go支援的運算子:

  2. 算術運算子

  3. 關係運算符
  4. 邏輯運算子
  5. 賦值運算子
  6. 位運算子
  7. 指標運算子

  8. 運算子的優化級

  9. Go支援的控制結構:
  10. If語句
  11. For語句
  12. Switch語句