go語言快速入門教程

       go快速入門指南

                                                                                   by 小強,2019-06-13html

      go語言是目前很是火熱的語言,普遍應用於服務器端,雲計算,kubernetes容器編排等領域。它是一種開源的編譯型程序設計語言,支持併發、垃圾回收機制以提高應用程序性能。它既具備像c這種靜態編譯型語言的高性能,又具有像python這種動態語言的高效性。不少go程序員都是從C++,Java等面嚮對象語言由於工做的須要轉過來的,所以沒有必要從0開始學習go,當初本身的想法是找一篇半小時入門go的博客,貌似沒有相似的好文章=_=。搜到的都是一些從小白入手的臃腫教程,學習起來太慢!!!so,打算寫這篇go語言快速入門的指南。python

       本文寫做思路重點在於和C++語言的不一樣之處入手,強調go的特性,注重快速入門,所以不介紹一些很是基礎的知識,很是基礎的一些知識能夠去看go語言聖經。關於go環境的安裝配置以及vscode編輯器的配置在以前的博客已經介紹,請移步。本文總體組織結構以下:git

  1. go程序開發的通常結構
  2. 基本數據類型
  3. 變量的聲明和賦值
  4. 運算符和指針
  5. 判斷語句if和循環語句for
  6. 數組、切片、map
  7. 函數function
  8. 方法、接口、反射
  9. 併發

 1.go程序開發的通常結構


    在學習任何一門語言的時候,首先都是給出hello world的示例,所以本文也難免俗,看看第一個go語言程序:程序員

/*1.1 template.go*/
//
當前程序的包名 package main //導入其餘的包 import ( "fmt" )//由main函數做爲函數入口 func main () { fmt.Println("Hello World!") }

  和python語言很像,go程序都必須包含在一個包package中,go程序通常由三部分組成:包聲明部分、第三方包導入部分和函數聲明部分。go語言使用關鍵字package聲明要建立的包;使用import導入第三方包;使用關鍵字func聲明要建立的函數。編程

       按照慣例,處於同一個文件裏的代碼文件,必須使用同一個包名,包和文件夾的名字相同。Go編譯器不容許聲明導入某個包卻不使用。使用下劃線可讓編譯器接收這類導入,而且調用對應包內的全部代碼文件中定義的init函數。 init函數會在main函數執行前執行。數組

1.1 編寫go程序步驟

  初學者按照如下步驟編寫go程序:緩存

  1)在工做目錄(好比D:\go\development)的src文件夾中建立源文件helloworld.go;.服務器

  2)直接將helloworld.go拖入vscode進行編輯;閉包

  3)在vscode的終端輸入go run helloworld.go,程序就會輸出hello world!併發

1.2 go的語法要點

  • go語言語句結束不使用分號,直接另起一行便可
  • go語言規定,函數、控制結構(if,for,switch)等的左大括號「{」必須和函數聲明或控制結構放在同一行
  • 可見性規則:go語言使用大小寫來決定常量、變量、類型、接口、結構或函數是否能夠被外部包所調用。  
    • 函數名首字母小寫,即爲private。
    • 函數名首字母大寫,即爲public。

2 .基本數據類型


  

  • 布爾型bool長度爲1字節,取值範圍true,false,不一樣點:注意不能使用數字0/1來表明true或者false
  • 整型:int/uint,根據運行平臺多是32或者64
    • 8爲整型:int8/uint8,長度是1字節,取值範圍:-128~127/0-255
    • 計算方法,2^8 / 2給負數部分,剩下分一個給0,最後的部分給整數部分。
    • int16/uint16,int32/uint32,int64/uint64
  • 浮點型:float32/float64
    • 長度:4/8字節,小數位,精確到7/15小數位
    • 注意go沒有double類型。
  • 複數:complex64/complex128
    • 長度:8/16字節
  • 足夠保存指針的32爲或64爲整數型:uintptr
  • 其餘值類型:array,struct,string
  • 引用類型:slice(切片,特有類型),map(哈希表),chan(通道)
  • 接口類型:interface
  • 函數類型:func

類型的零值:就是默認值,int默認是0,bool默認是false,字符串默認是空字符串。
類型別名方法格式:

//type 別名 基本類型
type byte int8

 

 

3.變量的聲明和賦值


  •  全局變量不能省略var關鍵字,函數內的變量聲明能夠省略。 go語言中使用關鍵字func聲明函數,關鍵字後面跟函數名、參數名以及返回值。

  • 全局變量的聲明可使用var()的方式進行簡寫
  • 全局變量的聲明不能夠省略var,可是可以使用並行方式
  • 全部變量均可以使用類型推斷
  • 局部變量不可使用var()的方式簡寫,只能使用並行方式。

3.1 變量聲明

  go語言使用關鍵字var來聲明變量,聲明的通常格式以下所示:

var <variableName> [varibleType]
var count int

 

  在聲明變量的同時可使用=給變量賦初值:

var count int = 10

  其中變量類型int也能夠省略,編譯器會依據賦的初值自動推斷變量類型:

var count = 10

  在聲明變量的同時還容許省略掉關鍵字「var」,使用":"取代。

count := 10

 

3.2 常量的聲明

  常量的聲明格式以下所示:

const <constName> [constType] = <賦值表達式>

 

  • 常量的值在編譯時就已經肯定
  • 常量的定義格式與變量基本相同
  • 等號右側必須是常量或者常量表達式
  • 常量表達式中的函數必須是內置函數
  • 在定義常量組是,若是不提供初始值,則表示將使用上行的表達式
  • 使用相同的表達式不表明具備相同的值
  • iota是常量的計數器,從0開始,組中每定義一個常量自動遞增1
  • 經過初始化規則與iota能夠達到枚舉的效果
  • 每遇到一個const關鍵字,iota就會重置爲0
  • 注意常量的定義必須是大寫字母。可是若是是大寫字母的話,就會變成public變量,爲了避免被包外部使用,通常在前面加_或者c。
const a = 1
const (
    b, c = 2,3
)
const d,f = 4,5
const (
    a = iota  //0
    b = iota  //1
)

 

4.運算符和指針


 4.1 運算符

    go的運算符均是從左至右結合。
    優先級(從高到底)

  • ^ !(一元運算符)
  • / % << >> & &^(二元運算符)
  • == != < <= >= >
  • <- (專門用於channel)
  • && (好處是運行第一個不知足要求就不在執行接下來的表達式)
  • ||

    其中位運算符介紹:

    實際例子:

6: 0110
11:1011
-------------
&: 0010
|: 1111
^: 1101
&^:0100

 

  • & 與:都是1的時候結果才能是1
  • | 或:只要有一個是1就是1
  • ^ 兩個只能有一個是1才能是1
  • &^第二個計算數是1的時候將第一個計算數對應位置爲0,若是第二個計算數該位是0的話,對應第一個計算數的位不變。

4.2 指針

    Go雖然保留了指針,但不一樣點在於go不支持指針運算以及->運算符,而直接採用.選擇符來操做指針目標對象的成員。

  • 操做符&去變量地址,使用*經過指針間接訪問目標對象
  • 默認值爲nil而非NULL
  • 遞增遞減語句
    在go當中,++ 與--是做爲語句而不是做爲表達式。必須單獨做爲一行,只能A++這種形式。
A++//只能做爲單獨的語句放在一行,且只能++放在右邊
x, y := 1, 2
var p = [2]*int{&x, &y}
fmt.Println(*p[0])

var arr = [2]int{x, y}
pf := &arr
fmt.Println(*pf)

    其實就是將[]*int當作一個類型,後面的{}就是初始化操做。

5.判斷語句if和循環語句for 


 5.1 判斷語句if

  • 條件表達式沒有括號
  • 支持一個初始化表達式(能夠是並行方式)
  • 左大括號必須和條件語句或else在同一行
  • 支持單行模式
  • 初始化語句中的變量爲block級別,同時隱藏外部同名變量
if a > 1 {
    fmt.Println(a)
}
if b :=1;b > 1 { }

注意else必須和if的右括號}在同一行才行,否則出錯。

if a {
    
}else {}

if後面定義的變量,屬於if語句的局部變量,只能在對應的if-else中使用,不能在外部使用。之間經過;分割語句。

5.2 循環語句for

  • go只有for一個循環語句關鍵字,但支持3種形式
  • 初始化和步進表達式能夠是多個值
  • 條件語句每次循環都會被從新檢查,所以不建議在條件語句中使用函數,儘可能提早計算好條件並以變量或常量代替。
  • 左大括號必須和條件語句在同一行
1. for init; condition; post {} // 和c語言的for同樣
2. for condition {} //while
3. for {}  //for(;;)

init: 通常爲賦值表達式,給控制變量賦初值;必定在這裏賦初值,否則出錯
condition: 關係表達式或邏輯表達式,循環控制條件;
post: 通常爲賦值表達式,給控制變量增量或減量。

for語句執行過程以下:
1)先對錶達式1賦初值;
2)判別賦值表達式init是否知足給定條件,若其值爲真,知足循環條件,則執行循環體內語句,而後執行post,進入第二次循環,再判別condition;不然判斷condition的值爲假,不知足條件,就終止for循環,執行循環體外語句。

  • for 循環的 range 格式能夠對 slice、map、數組、字符串等進行迭代循環。格式以下:
for key, value := range oldMap {
    newMap[key] = value
}

關鍵字range會返回兩個值,第一個值是當前迭代到的索引位置,第二個值是該位置對應元素值的一份副本。而不是返回對該元素的引用。

  • switch語句
    switch語句默認狀況下case最後自帶break語句,匹配成功後就不會執行其餘case,若是咱們須要執行後面的case,可使用fallthrough。
    其中var1能夠是任何類型,val1和val2能夠是同類型的任意值,類型不被侷限於常量或證書,但必須是相同的類型,或者最終結果爲相同類型的表達式。能夠同時測試多個可能符合條件的值,使用逗號分隔它們。例如 case val1,val2,val3。
switch var1 {
   case val1:
       ...
   case val2:
       ...
   default:
       ...
}

跳轉語句goto,break,continue

  • 三個語法均可以配合標籤使用。
  • 標籤名區分大小寫,若不適用會形成編譯錯誤。
  • Break與continue配合標籤可用於多層循環的跳出。
  • Goto是調整執行位置,與其餘2個語句配合標籤的結果並不相同。 標籤值是包含接下來的一個語句,continue是退出這個標籤的值。

6 .數組、切片、map


 6.1 數組

  定義數組的格式: var <varName> [n]<type> ,n >= 0(表示數組的元素個數)。

var a [2]int
var b [1]int

  記住ab是不一樣的類型,不能直接賦值,元素個數也是數組類型的一種。須要使用循環語句進行操做。 也能夠不指定數組元素的個數。

a := [...]int{1,2,3} //元素個數爲3個
a := [...]int{0:1,1:2}//位置0賦值爲1,位置1賦值爲2
a := new([10]int)
  • 數組長度也是類型的一部分,所以具備不一樣長度的數組爲不一樣類型。
  • 注意區分指向數組的指針和指針數組
  • 數組在go中爲值類型,不是引用類型,會所有拷貝值
  • 數組之間可使用==或!=進行比較,但不可使用<或>
  • 可使用new來建立數組,此方法返回一個指向數組的指針
  • go支持多維數組。

  須要注意的是全部值類型變量在賦值或做爲參數傳遞的時候將產生一次複製操做。若是將數組做爲函數的參數類型,則在函數調用是將該參數將發生數據複製,函數體內沒法修改數組的內容,由於函數體內操做是變量的一個副本。

  多維數組的聲明以下所示,其中第一維度行的數量是能夠省略的,使用...代替。

arr := [2][3]int{
    {1, 2, 3},
    {2, 3, 4}}
表示2個元素,每一個元素是一維數組,有三個元素。

 6.2 切片slice

  切片是數組的一個引用,它會生成一個指向數組的指針,並經過切片長度關聯到底層數組部分或者所有元素,還提供了一系列對數組的管理功能(append,copy),能夠隨時動態的擴充存儲空間。屬於變長數組,至關於C++的vector。建立切片的格式以下:

var sliceName []dataType

  建立切片時,不須要指定切片的長度。下面是一個具體的例子。

var slice1 []int

6.2.1 初始化方法

  1)若是引用底層數組的元素,初始化方法以下:

slice1 = array[start : end]

//如下是三種方式
slice1 = array1
slice1 = array1[ : ]
slice1 = array[0 : len(array1)]

  2)直接建立切片

  即在定義的同時初始化切片元素,以下例:

var slice1 = []int{1,2,3,4,5}

  3)使用make函數建立切片

  下式表示,建立整型切片slice1,元素個數爲5,元素初值爲0,並預留10個元素的存儲空間。

var slice1 = make([]int, 5, 10)

  對切片的訪問方式能夠經過下標的方式訪問,也能夠經過range關鍵字進行訪問,同數組。

  • 其自己並非數組,它指向底層的數組,使用[]來作聲明
  • 做爲變長數組的替代方案,能夠關聯底層數組的局部或所有
  • 屬於引用類型
  • 能夠直接建立或從底層數組獲取生成
  • 使用len()獲取元素個數,cap()獲取容量
  • 通常使用make()建立
  • 若是多個slice指向相同底層數組,其中一個的值改變會影響所有
  • make([]T,len,cap)
  • 其中cap能夠省略,則和len的值相同
  • len表示存數的元素個數,cap表示容量
//從數組初始化
var arr = [...]int{1,2,3}
var slice_a []int
slice_a = arr[1:2]//下標位置,[1,2),包括首位置,不包含末尾的2位置

 6.2.2 切片的操做

   - Reslice:

  • Reslice時索引以被slice的切片爲準
  • 索引不能夠超過被slice的切片容量的cap()值
  • 索引越界不會致使底層數組的從新分配而是引起錯誤

   - Append

  • 能夠在slice尾部追加元素
  • 能夠將一個slice追加在另外一個slice尾部
  • 若是最終長度未超過追到到slice的容量則返回原始slice
  • 若是超過追加到的slice的容量則將從新分配數組並拷貝原始數據
  • 使用...運算符將一個切片的全部元素追加到另外一個切片中
append(s1,s2...)

- copy

     copy(s1,s2),必須保證s1有足夠的空間來存儲s2的值。

- 多維切片

slice := [][]int{{1, 2}, {3, 4}}

     使用切片作值函數傳遞時,以值的形式傳遞切片,因爲切片的尺寸很小,因此成本很低,與切片關聯的數據保存在底層數組中,不屬於切片自己,因此切片的效率很高。slice的拷貝可使用 s2 := s1[:],拷貝首元素省略,拷貝末尾元素也能夠省略,:表示拷貝所有元素。

6.3 map 

  map就是理解爲C++裏面的map,是key-value類型,也稱爲字典或者哈希表。

6.3.1 聲明格式

var mapName map[keyType] valueType

var map1 map[string] int

  在該例中,聲明瞭一個鍵值類型爲字符串,值類型爲整型的字典map1。

6.3.2 字典的初始化和建立

  使用「{ }」操做符對字典進行初始化操做,或者使用make()函數來建立字典。初始化或者建立後,就可使用「=」操做符對字典動態的增添數據項了。

var map1 map[string] int {}
map1["key1"] = 1

  也可使用下面的方式進行建立:

var map1 map[string] int
map1 = make(map[string] int)
map1["key1"] = 1

6.3.3 map的訪問和操做

  map經過key來訪問value,訪問格式以下所示:

Value = mapName[Key]

  map的查找:若是查找的key存在,則將key對應的value值賦予v,OK爲true,反之,若是Key不存在,則v等於0,OK爲false。

v,OK := mapName[Key]

  map的刪除

  delete()用於刪除容器內的元素,也能夠用於刪除map內的鍵值對,例如:

  下面將從map1中刪除鍵值爲key1的鍵值對,若是key1這個鍵不存在,那麼這個調用將什麼也不會發生。

delete(map1,「key1」)
  • 相似其餘語言中的哈希表或者字典,以key-value形式存儲數據

  • key必須是支持==或!=比較運算的類型,不能夠是函數、map或者slice

  • map查找比線性搜索快不少,但比使用索引訪問數據的類型慢100倍

  • map使用make()建立,支持:=這種簡寫方式。

  • make([keyType]valueType,cap),cap表示容量,可省略

  • 超出容量時會自動擴容,但儘可能提供一個合理的初始值

  • 使用len()獲取元素個數

  • 鍵值對不存在時自動添加,使用delete()刪除某鍵值對

  • 使用for range對map和slice進行迭代操做

  • 記住每一個map都必須進行單獨的初始化操做。 使用make進行初始化操做。有幾層map就須要使用幾回make進行初始化操做。

  • map的迭代操做
for k,v := range m {}

7.函數function


 

  • go函數不支持嵌套,重載和默認參數
  • 但支持如下特性
    • 無需聲明原型 、不定長度變參、多返回值、命名返回值參數
    • 匿名函數、閉包
  • 定義函數使用關鍵字func,且左大括號不能另起一行
  • 函數也能夠做爲一種類型使用
  • 函數聲明的基本結構以下:
func functionName(參數列表) 返回值 {
    functionBody
        .
        .
        .
    return 語句
}
  • 不定長變參的使用
    不定長變參使用...表示,要放在全部的參數最後面,傳入的a變爲一個slice
func A (a ...int) {}
  • 閉包closure
    閉包就是在一個函數中聲明一個匿名函數,而後返回這個匿名函數。
func f(i int) func() int {
     return func() int {
         i++
         return i
     }
}
  • defer
    •  執行方式相似其餘語言的析構函數,在函數體執行結束以後按照調用順序的相反順序逐個執行
    •  即便函數發生嚴重錯誤也會執行
    •  支持匿名函數的調用
    •  經常使用於資源清理、文件關閉、解鎖以及記錄時間等操做
    •  經過與匿名函數配合可在return以後修改函數計算結果
    •  若是函數體內某個變量做爲defer時匿名函數的參數,則在定義defer時即已經得到了拷貝,不然則是引用某個變量的地址。
    •     go沒有異常機制,但有panic/recover模式來處理錯誤
    •     panic能夠在任何地方引起,但recover只有在defer調用的函數中有效

      defer,panic,recover

       go中能夠拋出一個panic的異常,而後在defer中經過recover捕獲這個異常,而後正常處理

func B() {
    defer func() {
        if err := recover(); err != nil {
            fmt.Println("Recover in B")
        }
    }()
    panic("Panic in B")
}
  • 代碼分析
func main() {
    var fs = [4]func(){}

    for i := 0; i < 4; i++ {
        defer fmt.Println("defer i = ", i)
        defer func() {
            fmt.Println("defer_closure i = ", i)
        }()
        fs[i] = func() { fmt.Println("closure i = ", i) }
    }

    for _, f := range fs {
        f()
    }
}

由於defer是逆序執行的,在i變爲4以後,閉包中指向的是i的地址,因此閉包中的i的值都是指向i=4的地址。

8 方法、接口和反射


 

8.1 方法

go語言的method相似於一個函數,只是函數名前多了個綁定類型參數---receiver,基本格式以下:

func (recv receiver_type) methodName (參數列表)(返回值){...}
  • 記住命名規範,在結構體中的字段名和方法名必須首字母大寫

    method中的receiver能夠是內置類型、自定義類型、結構體或指針類型。

  • go雖沒有class,可是有method
  • 經過顯示說明receiver來實現與某個類型的組合
  • 只能爲同一個包中的類型定義方法
  • receiver能夠是類型的值或者指針
  • 不存在方法重載
  • 可使用值或指針來調用方法,編譯器會自動完成轉換
  • 從某種意義來講,方法是函數的語法糖,由於receiver其實就是方法所接收的第一個採納數
  • 若是外部結構和嵌入結構存在同名方法,則優先調用外部結構的方法
  • 類型別名不會擁有底層類型所附帶的方法
  • 方法能夠調用結構中的非公開字段

  不一樣包中大小寫變量方法纔有權限的區別,同一個包中能夠訪問private字段的內容,大寫的public權限能夠被不一樣包之間訪問。type tz int,記住tz i和int i仍是不一樣的類型,前面的i屬於tz類型。要二者相加必須使用強制類型轉換。

8.2 接口

  • 接口是一個或多個方法簽名的集合
  • 只要某個類型擁有該接口的全部方法簽名,即算實現該接口,無需顯示聲明實現了哪一個接口,這稱爲Structural Typing
  • 接口只有方法聲明,沒有實現,沒有數據字段
  • 接口能夠匿名嵌入其餘接口,或嵌入到結構中
  • 將對象賦值給接口時,會發生拷貝。而接口內部存儲的是指向這複製品的指針,既沒法修改複製品的狀態,也沒法獲取指針
  • 只有當接口存儲的類型和對象都爲nil時,接口才等於nil
  • 接口調用不會作receiver的自動轉換
  • 接口一樣支持匿名字段方法
  • 接口也可實現相似oop中的多態
  • 空接口能夠做爲任何類型數據的容器

接口是用來定義行爲的類型,這些被定義的行爲不禁接口直接實現,而是經過方法由用戶定義的類型實現。
類型斷言

  • 經過類型斷言的ok pattern能夠判斷接口中的數據類型
  • 使用type switch則可針對空接口進行比較全面的類型判斷

接口轉換

  • 能夠將擁有超集的接口轉換爲子集的接口

8.3 反射reflection

  • 反射可大大提升程序的靈活性,使得interface{}有更大的發揮餘地
  • 反射使用type()和valueof函數從接口中獲取目標對象信息
  • 反射會將匿名字段做爲獨立字段
  • 想要利用反射修改對象狀態,前提是interface.data是settable,即pointer-interface
  • 經過反射能夠動態調用方法

  MethodByName()方法使用原對象的方法名name獲取該方法的Value值,若是所訪問的方法不存在,MethodByName會返回0.
在go語言中傳遞給方法的參數要和方法定義的參數類型保持一致,爲了處理變參這種複雜狀況,傳遞給被調用方法的參數一般首先保存在一個Slice中,而後在複製到參數列表中。

9.併發


  • 協程coroutine
    協程本質是一種用戶態線程,不須要操做系統進行搶佔性調度,並且在真正執行的時候中寄存於線程中。所以,協程系統開銷極小,能夠有效提升線程任務的併發性,避免高併發模式下線程併發的缺點。協程最大的優點在於輕量級,能夠輕鬆建立上百萬個而不是致使系統資源衰竭,系統最多能建立的進程、線程的數量卻少的可憐。使用協程的優勢是編程簡單,結果清晰。可是缺點就是須要語言的支持,若是語言不支持,則須要用戶在程序中自行進行調度。
  • 定義普通函數以後,調用時候前面加上go關鍵字就能夠了。
  • 通道Channel
    • Channel是goroutine溝通的橋樑,大都是阻塞同步的
    • 經過make進行建立,close關閉
    • channel是引用類型
    • 可使用for range來迭代不斷操做channel
    • 能夠設置單向或雙向通道
    • 能夠設置緩存大小,在未被填滿前不會發生阻塞
    • Select
      • 可處理一個或多個channel的發送與接收
      • 同時有多個可用的channel時按隨機順序處理
      • 可用空的select來阻塞main函數
      • 可設置超時
var varName chan elementType
var c chan int //和普通變量相比,只是增長了一個chan
ch := make(chan int) // 使用make函數直接聲明並初始化channel

9.1 channel數據的接收和發送

Channel的主要用途是在不一樣的Goroutine之間傳遞數據,它使用通道運算符<-接收和發送數據,將一個數據發送(寫入)至channe的方法是 ch <- value

  • 向Channel寫入數據一般會致使程序阻塞,知道其餘Goroutine從這個Channe中讀取數據,從Channel中接收(讀取)數據的語法以下: value := <- ch
    若是沒有寫入數據,那麼在讀取的時候也會阻塞,直到寫入數據爲止。
  • 關閉Channel的方法close(chanName),在關閉一個channel以後,用戶還須要判斷Channel是否關閉,可使用多重返回值的方法:
value,ok := <- ch

只須要看第二個bool返回值極客,若是返回值是false則表示Channel已關閉。

  • 只有發送端(另外一端正在等待接收)才能關閉Channel,只有接收端才能得到關閉狀態,Close調用不是必需的,可是若是接收端使用range或者循環接收數據,就必須調用Close,不然就會致使「throw: all gorountines are asleep-deadlock」
  • 單向Channel
    • 只能接收的Channel變量定義格式var chanName chan <- ElementType
    • 只能發送的Channel變量定義格式var chanName <- chan ElementType 在定義了Channel以後,還須要對其進行初始化操做,能夠由一個已定義的雙向Channel轉換而來。
ch := make(chan int)
chRead := <- chan int(ch)
chWrite := chan <- int(ch)

- 異步Channel
        在Goroutine間傳輸大量數據的時候,可使用異步通道(Asynchronous-channel),類比消息隊列的效果。
異步Channel就是給Channel設定一個buffer值,在buffer未寫滿的狀況下,不阻塞發送操做。buffer指的是被緩衝的數據對象的數量,而不是指內存大小。

  • 異步Channel的建立方法:ch := nake(chan int,1024)該例建立了一個1024的int類型的Channel。

9.2 select機制和超時機制

select機制每一個case語句必須是一個I/O操做,其基本結構以下:

select {
    case <- chan1:
        //若是chan1成功讀取數據,則進行該case處理語句。
    case <- chan2:
        //若是chan2成功讀取數據,則進行改該case處理語句。
    default:
        // 若是上面都沒有成功,則進入default處理流程。
}
  • 超時機制超時機制是一種解決通訊死鎖問題的機制,一般會設置一個超時參數,通訊雙方若是在設定的時間內仍然沒有處理完任務,則該處理過程就會被終止,並返回對應的超時信息。
相關文章
相關標籤/搜索