首頁 > 軟體

淺析Go語言中Channel的各種用法

2022-11-25 14:00:23

Go語言基礎四

今天我們要來學習if語句,也就是大家口中的判斷語句,我們首先來看一下if語句的定義

if定義

條件語句需要開發者通過指定一個或多個條件並通過測試條件是否為 true 來決定是否執行指定語句,並在條件為 false 的情況在執行另外的語句。相信讀者看到這兒,也是雲裡霧裡的感覺,我們怎麼來表示truefalse呢?

單層if語法格式

  • 可省略條件表示式括號。
  • 持初始化語句,可定義程式碼塊區域性變數。 
  • 程式碼塊左 括號必須在條件表示式尾部。

    if 布林表示式 {
    /* 在布林表示式為 true 時執行 */
    }  

這裡要為讀者介紹的是,如果if後面的條件語句程式給出的數能夠滿足,則我們表示為true;如果不能,則返回false

package main
​
import "fmt"
​
func main() {
   a := 3
   if a > 2 {
      fmt.Println("true")
   } else {
      fmt.Println("false")
   }
}

如程式碼塊所示,這裡我們定義了一個變數a的值為3,接下來是一個if判斷,如果該數值>2,則呼叫函數列印輸出true;否則返回false。換句話說,我們這裡即是對a變數的一個判斷,至於呼叫函數列印輸出的內容,由讀者自行決定

語法警告

在Go語法中,不支援三元操作符(三目運運算元) a > b ? a : b,如果讀者對三元運運算元較感興趣,可以移步至java瞭解三元運運算元(其本質上也是一種if判斷形式

package main
​
import "fmt"
​
func main() {
   /* 定義區域性變數 */
   var a int = 10
   /* 使用 if 語句判斷布林表示式 */
   if a < 20 {
       /* 如果條件為 true 則執行以下語句 */
       fmt.Printf("a 小於 20n" )
   }
   fmt.Printf("a 的值為 : %dn", a)
}  

上方是關於if判斷的一個小練習,讀者自行體會即可;if 在布林表示式為 true 時,其後緊跟的語句塊執行,如果為 false 則執行 else 語句塊。

package main
import "fmt"
func main() {
   /* 區域性變數定義 */
   var a int = 100
   /* 判斷布林表示式 */
   if a < 20 {
       /* 如果條件為 true 則執行以下語句 */
       fmt.Printf("a 小於 20n" )
   } else {
       /* 如果條件為 false 則執行以下語句 */
       fmt.Printf("a 不小於 20n" )
   }
   fmt.Printf("a 的值為 : %dn", a)
}

Go語言中,if語句也支援巢狀處理,即可以實現多重if判斷以達到程式想要的結果

多層if語法格式

if 布林表示式 1 {
   /* 在布林表示式 1 為 true 時執行 */
   if 布林表示式 2 {
      /* 在布林表示式 2 為 true 時執行 */
   }

package main
​
import "fmt"
​
func main() {
   /* 定義區域性變數 */
   var a int = 100
   var b int = 200
   /* 判斷條件 */
   if a == 100 {
       /* if 條件語句為 true 執行 */
       if b == 200 {
          /* if 條件語句為 true 執行 */
          fmt.Printf("a 的值為 100 , b 的值為 200n" )
       }
   }
   fmt.Printf("a 值為 : %dn", a )
   fmt.Printf("b 值為 : %dn", b )
}     

如上圖所示,我們在if語句裡面巢狀了另一個if語句,即是在預設a == 100的情況下寫出對變數b的值的判斷,最終呼叫函數列印輸出a和b的值

有時候我們多個變數匹配同一個值,就會用到Switch語句

Switch定義

switch 語句用於基於不同條件執行不同動作,每一個 case 分支都是唯一的,從上直下逐一測試,直到匹配為止。Golang switch 分支表示式可以是任意型別,不限於常數。可省略 break,預設自動終止。

Switch語法格式

switch var1 {
    case val1:
        ...
    case val2:
        ...
    default:
        ...
}
package main
import "fmt"
func main() {
   /* 定義區域性變數 */
   var grade string = "B"
   var marks int = 90
​
   switch marks {
      case 90: grade = "A"
      case 80: grade = "B"
      case 50,60,70 : grade = "C"
      default: grade = "D"  
   }
​
   switch {
      case grade == "A" :
         fmt.Printf("優秀!n" )     
      case grade == "B", grade == "C" :
         fmt.Printf("良好n" )      
      case grade == "D" :
         fmt.Printf("及格n" )      
      case grade == "F":
         fmt.Printf("不及格n" )
      default:
         fmt.Printf("差n" )
   }
   fmt.Printf("你的等級是 %sn", grade )
}    

由上方程式碼塊可知,我們定義了兩個區域性變數grademarks,對marks進行Switch判斷操作,當case滿足不同的值的時候,呼叫函數列印輸出的值也不一樣

Type Switch

switch 語句還可以被用於 type-switch 來判斷某個 interface 變數中實際儲存的變數型別

Type Switch語法格式

switch x.(type){
    case type:
       statement(s)      
    case type:
       statement(s)
    /* 你可以定義任意個數的case */
    default: /* 可選 */
       statement(s)
} 

由於Type Switch用途不是特別的多,作者在這裡不作詳細描述,讀者可以去官網自行查詢相關檔案進行學習

Select定義

  • select 語句類似於 switch 語句,但是select會隨機執行一個可執行的case。如果沒有case可執行,它將阻塞,直到有case可執行。
  • selectGo中的一個控制結構,類似於用於通訊的switch語句。每個case必須是一個通訊操作,要麼是傳送要麼是接收
  • select 隨機執行一個可執行的case。如果沒有case可執行,它將阻塞,直到有case可執行。一個預設的子句應該總是可執行的

Select語法格式

select {
    case communication clause  :
       statement(s);      
    case communication clause  :
       statement(s);
    /* 你可以定義任意數量的 case */
    default : /* 可選 */
       statement(s);
} 

Select語句注意事項

  • 每個case必須是一個通訊
  • 所有channel表示式都會被求值
  • 所有被傳送的表示式都會被求值
  • 如果任意某個通訊可以進行,它就執行;其他被忽略
  • 如果有多個case都可以執行,Select會隨機公平地選出一個執行。其他不會執行。
  • 如果有default子句,則執行該語句。
  • 如果沒有default字句,select阻塞,直到某個通訊可以執行;Go不會重新對channel值重新進行求值。
package main
​
import "fmt"
​
func main() {
   var c1, c2, c3 chan int //通道機制
   var i1, i2 int
   select {
   case i1 = <-c1:
      fmt.Printf("received ", i1, " from c1n")
   case c2 <- i2:
      fmt.Printf("sent ", i2, " to c2n")
   case i3, ok := (<-c3): // same as: i3, ok := <-c3
      if ok {
         fmt.Printf("received ", i3, " from c3n")
      } else {
         fmt.Printf("c3 is closedn")
      }
   default:
      fmt.Printf("no communicationn")
   }
}

根據上方程式碼所示,定義了c1、c2、c3三個變數,並且使用chan通道。關於寫法的解釋:一個可以傳送 int 型別資料的 channel 一般寫為 chan int,根據上方的語法規則:如果有default子句,則執行該語句,故上方程式碼塊執行程式碼為:no communication

Select用法補充

  • 我們可以使用select來監聽channel的資料流動
  • select的用法與switch語法非常類似,由select開始的一個新的選擇塊,每個選擇條件由case語句來描述
  • switch語句可以選擇任何使用相等比較的條件相比select由比較多的限制,其中最大的一條限制就是每個case語句裡必須是一個IO操作
  • 如果每個 case都未讀取到,則Go語言會自動讀取default語句所描述的東西,在正常情況下,每個select程式都會有一個輸出語句
  • 如果既沒有case語句滿足,也不存在default語句,則程式進入阻塞狀態系統會發出警告,直至疏通

超時判斷

var resChan = make(chan int)
// do request
func test() {
    select {
    case data := <-resChan:
        doData(data)
    case <-time.After(time.Second * 3):
        fmt.Println("request time out")
    }
}
​
func doData(data int) {
    //...
}

根據上方程式碼塊可知,我們定義了一個select語句,在第一條case裡面,我們將resChan傳給data如果在傳輸的過程中時長超過3s,則會執行第二條case語句

退出

var shouldQuit=make(chan struct{})
fun main(){
    {
        //loop
    }
    //...out of the loop
    select {
        case <-c.shouldQuit:
            cleanUp()
            return
        default:
        }
    //...
}
​
//在另外一個協程中,如果執行遇到非法操作或不可處理的錯誤,就向shouldQuit傳送資料通知程式停止執行
close(shouldQuit)

我們定義一個var型別的shouldQuit變數用於結構體的通道,首先我們開啟一個select迴圈,在case裡面呼叫通道方法,並且返回所對應的值;如果不滿足,則返回default的值。同時我們在另外一個協程中,如果我們遇到了非法操作或不可處理的錯誤,就向shouldQuit傳送資料通知程式停止執行

判斷Channel狀態

ch := make (chan int, 5)
//...
data:=0
select {
case ch <- data:
default:
} 

有時候我們不喜歡快取變慢,這樣不利於我們去釋放資源,因此我們可以用一個簡單的判斷方法去進行判斷:首先我們開啟一個int型別,長度為5的通道,在通道里面我們開啟一個select迴圈,如果data通道的值能被ch所接收,則執行該條語句,否則我們可對default語句進行拋棄data等處理操作

到此這篇關於淺析Go語言中Channel的各種用法的文章就介紹到這了,更多相關Go語言Channel用法內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com