【Go學習】Go(Golang)知識點總結

兔兔西發表於2019-01-03

1,Go介紹

是Google開發的一種靜態強型別、編譯型、併發型,並具有垃圾回收功能的程式語言。

1)環境搭建

①標準包安裝

go1.11.2.darwin-amd64.pkg
檢查安裝成功:在終端輸入:go,出現go命令列表。

②配置環境變數

(1)開啟終端,cd ~
(2)檢視是否有.bash_profile檔案:
		ls -all
(3)有則跳過此步,沒有則:
   1)建立:touch .bash_profile
   2)編輯:open -e .bash_profile
   3)自定義GOPATH和GOBIN位置:
export GOPATH=/Users/lwh/program/Go
export GOBIN=$GOPATH/bin
export PATH=$PATH:$GOBIN
(4)編譯:source .bash_profile

終端輸入以下命令。顯示go執行所需的系統環境變數。

go env

③安裝整合開發工具(LiteIDE、Sublime Text、Vim、Emacs、Eclipse、vscode、goland)

Sublime Text3的gosublime這個外掛目前不能用,但是可以在github上下載,相比起來vscode有智慧提示所以採用vscode。

goland使用:
goland應該是最好用的,很少的配置,收費,不缺錢可以支援下正版。
i> 官網下載goland
ii> 新建一個project,選擇專案location。
如果go環境安裝成功goroot可以選擇。然後create專案。
在專案根目錄建立directory:main。然後在其下方寫一個新的程式:test.go。

package main
import (
       "fmt"
)
func main(){
       fmt.Println("hello world")
}

Control + shift + R執行即可。#

④工作空間

即建立GOPATH目錄,並在GOPATH下建立三個目錄:

bin:存放編譯後生成的可執行檔案(.exe)
pkg:存放編譯後生成的包檔案(.a)
src:存放專案原始碼(.go)

2,基本語法

1)常量、變數與命名規則

①可見性規則

函式名首字母小寫,表示private;
函式名首字母大寫,表示public。

②常量 const

執行期間不可改變值。
可以涉及計算,但每一個值必須是編譯期就能獲得。

1>內建常量

true、false、iota。

iota

初值為0,作為常量組中常量個數的計數器。

2>定義

const PI float32 = 3.1415926
const PI = 3.1415926   //隱式型別常量定義(省略常量型別,根據賦值自動判斷型別)
const a,b,c = 1, "Go", 'c'  //整型常量、字串常量、字元常量 多個常量一起定義

3>列舉

列舉指一系列的常量。

	const (
		Sunday  = iota //0  iota生成了從0開始自動增長的列舉值
		Monday         //1  後續的iota可以省略
		Tuesday        //2
	)
	const (
		A = iota //iota每遇到一個const關鍵字,就重置為0
		B
	)
	fmt.Println(Sunday);  //0
	fmt.Println(Monday);  //1
	fmt.Println(Tuesday); //2

	fmt.Println("-------");
	fmt.Println(A); //0
	fmt.Println(B); //1

③變數 var

執行期間可改變的值。
變數名是用來引用變數所儲存資料的識別符號,實際上代表變數在記憶體中的地址,可以使用&獲取。

1>定義

var count int = 10   //格式為:var <variableName> [variableType]
var count = 10 //預設
count: = 10  //用:代替var的預設

2>變數的型別零值

即初始化值。

型別 零值
bool false
int、float、byte\rune 0
complex 0+0i
string “”
pointer、function、interface、slice、channel、map nil

④識別符號命名規則

i> 以字母或下劃線開始
ii> 由字母、數字、下劃線組成
iii> 避免關鍵字
iv> 大小寫區分為不同的變數

2)資料型別

①基本資料型別

1> 布林型 bool (1 Byte)

取值範圍:true | false。

2> 整型

進位制(4種):

123  //十進位制
0123  //八進位制 以0開頭
0x123  //十六進位制  以0x開頭
1e3   //指數形式 由數字和e組成  1*(10^3) = 1000

有無符號整型:

int   //有符號整型
uint //無符號整型

精度控制整數:

型別 位元組長度 取值範圍
int 4/8 由作業系統決定。32位機:int32,64位機int64
int8 1 -128~127 (- 2^7 ~ (2^7 -1) )
int 16 2 - 2^15 ~ (2^15 -1)
int 32 4 - 2^31 ~ (2^31 -1)
int 64 8 - 2^63 ~ (2^63 -1)
- - -
uint 4/8
uint8 1 -128~127 (- 2^8 ~ (2^7) )
uint 16 2 ……
uint 32 4 ……
uint 64 8 ……
位元組型 byte(1byte) == uint8

本質是uint8的型別,使用效果完全一樣。
使用該別名是為了增強程式碼的可讀性,告知現在是進行位元組處理。
主要作用:表示和儲存ASCII碼,即處理字元。

字元型

字元以ASCII的形式儲存到記憶體中。所以一個byte型資料直接輸出就是uint8整數形式;也可以將對應的ASCII碼轉換成相應的字元。

rune型別 == int32

Go語言處理Unicode時專門的資料型別,完全等價於int32。
使用該別名是為了增強程式碼的可讀性,告知現在是進行Unicode字元處理。

3> 浮點型(實數)

表示形式:

1.25
1.23e3 
型別 位元組長度 精確位數
float32 32位浮點型 4 精確到小數點後7位
float64 64位浮點型 8 精確到小數點後15位

浮點數存在舍入誤差,所以避免極大數和極小數相加減丟失極小數。

4> 複數型

var cp complex64 = 1.2 + 3.4i    //複數:a+bi形式的數(i = 根號-1)。
real(cp)   //即1.2,fmt內建包計算實部的函式
imag(cp)   //即3.4,fmt內建包計算虛部的函式
型別 位元組長度
complex64 8
complex128 16

5> uintptr 指標型別

uintptr是可以儲存指標的無符號整數型別,可以儲存32位或64位的指標。根據作業系統決定指標位數。

//一般表現形式:var <指標變數名> * <基型別>   
var i_pointer * int                      //指向整型的變數的指標i_pointer
var i int = 100; i_pointer = &i             //將i的記憶體地址存放到i_pointer中
fmt.Println( * i_pointer )           //通過指標i_pointer讀取對應地址存放的資料,結果輸出為100。

使用注意:

  • 指標型別初始化預設值為nil,Go中沒有NULL常量。
  • Go中不支援指標運算。
  • Go不支援運算子,直接用.選擇符操作指標物件成員。

②值型別和引用型別

1>值型別

包括:bool、int、float、byte、複數型(complex)、字串(string)、陣列、結構體、錯誤型別(error)。
值拷貝傳遞。
字串(string)、陣列、結構體又稱為構造型別。

2>引用型別

包括:指標、切片(slice)、字典(map)、通道(channel)、介面(interface)、函式(function)。

③字串(string)

1> 字串內容不可變

2> 字串操作

       var str string = "hello"; //字串初始化
	fmt.Println(str[2]);      //取字元,以0開始。'A' = 65,'a' = 97, 輸出為l =  97+12 = 108
	fmt.Println(len(str));    //len()函式  輸出為5
	fmt.Println(str + " world");

3>字串遍歷

支援2種方式。

       var str string = "hello";
	//位元組陣列方式遍歷:(每一個字元型別為byte)
	for i := 0; i < len(str); i++ {
		fmt.Printf("str[%d] = %v\n", i, str[i]);
	}

	fmt.Println("-----------");
	//Unicode字元方式遍歷:(每一個字元型別為rune)
	for i, ch := range str {      
		fmt.Printf("str[%d] = %v\n", i, ch);
	}

4>strings 包

Go標準庫包。
包含了字串查詢函式、字串比較函式、字串位置索引函式、字串追加和替換函式

5>strconv 包

Go標準庫包。
提供了字串與基本資料型別相互轉化的基本函式。

④陣列型別

1>定義

陣列是一組具有相同型別和名稱的變數的集合。

var arr1 [5] int

陣列的元素型別必須是基本資料型別。

2>初始化

       var arr1 = [2] int {1,2}
	var arr2 = [2] int {1}
	var arr3 = [...] int {2,2} //...就是三個英文句號。這個不能省略,否則就成切片了

3>多維陣列

var a[3][4] int  //二維陣列定義
var a = [3][4] int {{1,2,3}, {4,5}, {6}} 

⑤切片(slice)(變長陣列)

是陣列的一個引用,它會生成一個指向陣列的指標,並通過切片長度關聯到底層陣列部分或者全部元素。
切片還提供了一系列對陣列的管理功能,可以隨時動態的擴充儲存空間,並且可以被隨意傳遞而不會導致所管理的陣列元素被重複賦值。
故切片通常用於實現變長陣列。

1>切片原型

    type slice struct {
        array unsafe.Pointer      //Pointer 是指向一個陣列的指標
        len   int     //len 代表當前切片的長度
        cap   int   //cap 是當前切片的容量。cap 總是大於等於 len 的
    }

2>宣告

var slice1 [] int  //不要指定陣列長度即切片

3>初始化

預設為nil,長度為0.

var slice1 = [] int {1,2,3,4}
var slice1 = make([] int, 4)  //通過內建函式make建立有4個元素的整型切片,元素初始值為int的初始值0.
var slice1 = make([]int, 4, 10) //預留10個元素的儲存空間。

4>運算元組

slice1 = array1         //指定切片引用範圍為陣列全部
slice1 = array1[ : ]   //指定切片引用範圍從第一個元素到最後一個元素
slice1 = array1[m:n]  //指定切片引用範圍從第m個元素到第n個元素

5>操作

  • 訪問:利用下標
  • 元素增加:append()
  • 元素複製:copy()

⑥字典(Map,Dictionary,雜湊表Hash table)

由鍵值對組成。

1>初始化和建立

未初始化時值為nil。

var map1 map[string] int {}   //建立並初始化。鍵用[]包起來。
map1["key1"] = 1

或者用make函式

var map1 map[string] int      //建立
map1 = make( map[string] int)   //初始化,給map1分配儲存空間

2>訪問和操作

查詢:

	var map1 = map[string]int{"key1": 100, "key2": 200}
	v, OK := map1["key1"] //查詢一個特定的鍵值對。如果key值存在,則將Key對應的Value值賦予v,OK為true。否則v=0,OK為false。
	if OK {
		fmt.Println(v, OK) //輸出:100 true
	} else {
		fmt.Println(v)
	}

刪除:

delete(map1,"key1")

⑦通道型別

⑧錯誤型別

⑨型別別名

使用type關鍵字為型別定義別名。

	type(
		word uint //定義word是uint的別名
		小數 float32 //Go支援UTF-8程式設計格式,所以定義時可用非英文字元。
	)
	var f 小數 = 3.14
	var i word = 3
	fmt.Println(f)
	fmt.Println(i)

⑩型別轉換

格式:<變數A>[:] = <變數A的型別>(<變數B>)

	var a int
	var f float32 = 3.14
	a = int(f)   //如果變數A已經定義過了,可以省略`:`
	b := int(f)  
	fmt.Println(a)
	fmt.Println(b)

3)運算子與表示式

①分號

用分號來終止語句,但這個分號可以由詞法分析器掃描原始碼過程中自動插入(給每一行末尾根據簡單的規則進行判斷是否需要加分號,所以出現了左大括號約定)。

②註釋

//
或
/*   */

③位運算子

運算子 描述 說明
^ 取反
&
|
&^ 標誌位清除運算子 從a上清除b上的標誌位
<< 左移
>>
	var a, b byte = 10, 4 //1010

	fmt.Println(a)      //10b
	fmt.Println(^a)     //11110101b   2^8-1-10 = 256-11 = 245
	fmt.Println(a &^ b) //1010b 清除 10b = 1000b = 8 ;1010b 清除 100b = 不變 = 1010b = 10
	fmt.Println(a << 1) //10*2 = 20

④通道運算子(< -)

詳細用法可見通道。

4)輸入輸出

①標準輸出函式:

1>Print

2>Println

3>Printf 格式化輸出

原型:func Printf( format string, a...interface{} ) (n int, err error)
會返回輸出的位元組數和錯誤型別。

作用物件 格式字元 說明
- %v 以基本格式輸出
- %#v 輸出資料,同時也輸出Go語法表示
- %T 輸出資料型別
- %% 輸出%
bool %t 輸出布林值true flase
int %b、%d、%o、%x、%X 以二進位制、十進位制、八進位制、十六進位制(小寫)、十六進位制(大寫) 輸出
int %c 以Unicode字元格式輸出(否則直接輸出為ASCII碼)
int %q 輸出的每個字元自動加單引號
int %U Unicode格式:U+1234 == U+%04X
浮點型、複數 %b 無小數部分、兩位指數的科學記數法
浮點型、複數 %e、%E 科學計數法(小寫e、大寫E)
浮點型、複數 %f 有小數部分,但無指數部分
浮點型、複數 %g、%G 根據實際情況採用%e(%E)或%f
字串、切片 %s 直接輸出字串或切片
字串、切片 %q 輸出字串的同時加雙引號
字串、切片 %x、%X 每個位元組用兩字元的十六進位制數表示
指標 %p 以0x開頭的十六進位制數表示
- + 輸出數值正負號對%q(%+q)按ASCII碼輸出
- - 使用空格填充右側空缺(預設為左側)
- #
- ‘ ’
- 0 用前置0代替空格填補空缺
fmt.Printf("str[%d] = %v\n", i, str[i]);

②標準輸入函式

1>Scan

原型:

func Scan(a ...interface{} )( n int, err error )

將使用空格分割的連續資料順序存入到引數中(換行也被視為空格)。返回引數的數量n。

	var a,b,c int
	fmt.Scan(&a,&b,&c)

2>Scanln

原型:

 func Scanln(a ...interface{} ) ( n int, err error)

同Scan,不同的是Scanln讀取到換行符才終止錄入。

3>Scanf

原型:

func Scanf( format string, a ...interface{} )( n int, err error}

按照格式化字元讀取資料。

       var a,b,c int
	fmt.Scanf("%d,%d %d",&a,&b,&c)  //嚴格按照格式輸入才可以讀取,如‘1,2 3’
	fmt.Print(a)
	fmt.Print(b)
	fmt.Print(c)

5)順序結構程式

複合語句

用花括號{}將多條語句組合在一起。
複合語句中的定義的變數是區域性變數,作用域為整個複合語句。

6)選擇結構程式

①if-else

if 表示式1 {
} else if 表示式2 {
} else

注意:if語句塊中不允許執行return語句。

②switch

switch 條件表示式 {
case 常量1:
       語句1
      ……
default:
       語句n
}
或者:
switch{
case 條件表達1:
    語句1
      ……
default:
       語句n
}

注意:
1>case語句後面不需要break,執行完自動跳出switch語句。
2>如果想執行完當前case後,繼續執行下一個case,在case塊最後面新增語句:fallthrough

	var op byte = '+';
	switch op {
	case '+':
		fmt.Println(1);
		fallthrough
	case '-':
		fmt.Println(2)
	}

7)迴圈結構程式

只有for迴圈,沒有do和while迴圈。
注意for語句後面沒有括號。

好的程式設計習慣:

  • 迴圈變數名儘量短,如:i, j, z, ix等。
  • 不要在迴圈中修改迴圈變數

①for基本迴圈結構

      var str string = "hello";
	for i := 0; i < len(str); i++ {
		fmt.Printf("str[%d] = %v\n", i, str[i]);
	}

執行順序:表示式1,表示式2,表示式4,表示式3

for 表示式1; 表示式2; 表示式3 {
      表示式4
}

②for條件迴圈結構

類似while迴圈。

for 條件表示式{
}

③for無限迴圈結構

用break跳出迴圈。

for{
}
for true{}
for ; ; {}

④for range語句

相當於迭代器,可以對陣列(Array)、切片(Slice)、字典(Map)、通道(Channel)等進行遍歷。在遍歷時會返回一個鍵值對。

       var str string = "hello";
	for i, ch := range str { //返回的鍵值對i,ch  i為下標,ch為值。
		fmt.Printf("str[%d] = %v\n", i, ch);
	}

可以使用佔位符過濾掉不需要資料。

for _,ch := range str{}   //只需要值不需要鍵

for i, _ := range str {}   //只需要鍵不需要值
for i := range str {}   //只需要鍵不需要值

⑤跳轉語句

1> goto

與LABEL搭配使用。

       var a int = 1;
	goto LABEL1

	a++

	LABEL1:
		fmt.Println(a);

2> break

3> continue

8)函式

①包宣告部分

包是組成的Go程式的基本單位。每個Go原始碼都要進行包宣告說明當前檔案屬於哪個包。

package <pkgName>

可執行Go程式有且僅有一個main包,有且僅有一個main函式(在main包中)。
原始碼編譯後都會生成*.a檔案。

②第三方包匯入部分

分為如下三種模式。匯入的包沒有使用編譯會報錯(保證程式碼體積小,加快編譯速度)。

1>正常模式

import <pkgName>  

舉例:

import "fmt" //匯入包
fmt.Println(v, OK) //輸出:100 true   //包內函式呼叫

2>別名模式

包名相近或相同用別名區分。

import 別名 <pkgName>

3>簡便模式

import . <pkgName>

③函式宣告部分

func為關鍵字。允許多返回值。

func funcName(引數列表)(返回值列表){
       return result1, result2
}

main函式沒有引數也沒有返回值,如果要傳入引數,可在os.Args變數中儲存。

④變參傳遞

任意數量:

func main() {
	a(1,2,3,4,5);
}
func a(args ... int){ 
	fmt.Println(args) //輸出[1 2 3 4 5]
	fmt.Println(args[2:]) //輸出[3 4 5] 從索引2開始的數字
}

任意型別的變參,型別指定為空介面interface{}:

func main() {
	a(1,2,"s",4,5);
}
func a(args ... interface{}){
	fmt.Println(args) //輸出[1 2 s 4 5]
}

⑤閉包(Closure)

內部函式通過某種方式使其可見範圍超出了其定義範圍。
在go語言中,閉包可以作為函式物件或匿名函式。確保只要閉包還被使用,那麼被閉包引用的變數會一直存在。

⑥defer語句

通過defer向函式註冊退出呼叫,當主調函式退出時,defer後的函式才會被執行(不管是否出現異常都會被執行)。

1>最後呼叫

	defer fmt.Println("defer ")
	fmt.Println("main ")

輸出:
main defer

2>倒序輸出

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

輸出:3210

3>匿名函式呼叫

func main() {
	fmt.Println("f1 = ",f1())
	fmt.Println("f2 = ",f2())
}
//一個延遲執行的函式的變數的值在宣告時,值不延遲
func f1() int{
	var i int
	defer fmt.Println(i)
	i = 1
	return 1
}
//被延遲的匿名函式會讀取f2的返回值,或對f2的返回值賦值
func f2()(i int){
	defer func(){
		i++
	}()
	return 1
}

4>用於清理工作

defer語句常用來進行函式的清理、釋放資源等工作。

srcFile,err := os.Open("myFile")
defer srcFile.Close

9)結構體

①使用

Go沒有類的概念,通過結構體來實現物件導向程式設計。

type date struct {//定義
	year int
}
type student struct {
	id int
	name string
	birthday date
}
func main() {
	stu := new(student)
	stu.name = "a"    //訪問
	stu.id = 0
	stu.birthday.year = 5

	fmt.Println(stu)
}
stu := student{0,"a",date{1}}  //物件初始化

②嵌入式結構

③匿名欄位

④方法

1>定義

在普通的函式名前增加繫結型別引數。


type student struct {
	id int
	name string
	fee int
}
type teacher struct {
	id int
	name string
	fee int
}
func main() {
	stu := student{0,"a",10}
	t1 := teacher{0,"a",10}

	fmt.Println(stu.getFee())
	fmt.Println(t1.getFee())
}
func (revc student) getFee() int{    //rev為變數,student為struct型別。
	return 10+100
}
func (revc teacher) getFee() int{    //類似java中的多型。接收型別不同,方法名可以一樣
	return 10+1000
}

如果指標作為一個receiver,那麼是一個引用傳遞。

2>匿名Receiver

3>繼承和重寫

type people struct {
	id int
	name string
	fee int
}
type student struct {
	people
	school string
}
func main() {
	stu := student{people{0,"a",10},"ut"}

	fmt.Println(stu.getFee())
}
func (revc student) getFee() int{ //重寫了方法,隱藏了people的getFee方法
	return 10+100
}
func (revc people) getFee() int{
	return 10+1000
}

4>欄位標籤

10)介面(Interface)

是一組Method的組合,通過Interface來定義物件的一組行為。

①定義

type Speaker interface {  //關鍵字:type interface
	sayHi()
}
func (s student)sayHi(){
	
}
func (s student)study(){

}

②介面組合

集合其他介面的功能

type SpeakerLearner interface {
	Speaker
	study()
}

③空介面

表示任何資料型別。

interface{}

④使用

⑤反射

3,包

1)fmt

是format縮寫。內建基本包。

Package fmt implements formatted I/O with functions analogous to C’s printf and scanf. The format ‘verbs’ are derived from C’s but are simpler.

2)math

①Min、Max

Max(int8)  Min(int8)  //資料的最大值最小值

3)strings包

4)strconv包

5)bytes包(位元組切片標準庫)

提供了對位元組切片進行讀寫操作的一系列函式和方法。包括:位元組切片處理函式、Buffer物件和Reader物件,類似於strings包。

6)bufio包

實現了對資料I/O介面的緩衝功能。
封裝於介面io.ReadWriter、io.Reader和io.Writer中,在提供緩衝的同時實現了一些文字的基本I/O操作功能。

4,加強

1)記憶體分配機制

①原始碼檔案

UTF-8格式。

②GC

標記-清除演算法。

③記憶體函式

GO有兩種分配記憶體機制,分別是使用內建函式new()和make()。

1>new()

用於給值型別的資料分配記憶體,呼叫成功後返回一個初始化的記憶體塊指標,同時該型別被初始化為“0”.

2>make()

用於給引用型別分配記憶體空間。
make函式建立的是一個引用型別物件,而不是一個記憶體空間的指標。

2)併發程式設計

①基本概念

1>OS提供的併發基礎

程式、
執行緒、
協程(使用者態執行緒):不需要OS進行搶佔式排程,在真正的實現中寄存於執行緒。

2>程式間的併發通訊

  1. 鎖原語操作
  2. 訊號量機制
  3. 共享記憶體(Shared Memory)
    多個併發單位在同時訪問共享記憶體時,必須使用互斥鎖等相關機制,保證對共享記憶體的互斥訪問。這早就程式設計複雜。
  4. 訊息通訊機制(Message Communication Mechanism)
    Go語言在處理程式的併發模型時,主要採用訊息機制。
    訊息機制規定每個併發單位是自包含的、獨立的個體,並且都有自己的變數,這些變數不能在不同的併發單位之間共享。每個併發單位的輸入輸出只有一種:訊息,即Channel。(類似程式的感覺)

②Goroutine(輕量級執行緒)

是Go語言執行庫的功能(由Go執行時管理(Runtime)),不是OS提供的功能(不是用執行緒實現的,所以支援跨平臺)。
Goroutine就是一段程式碼,一個函式入口,以及在堆上為其分配的一個堆疊。因為節省了頻繁建立和銷燬執行緒的開銷,所以對於程式、執行緒的開銷非常小。可以輕鬆建立上百萬個Goroutine,但它們不是被OS所排程執行的。
Go語言標準庫提供的所有系統呼叫操作(包括同步I/O操作),都會讓出處理機給其他Goroutine。

1>建立(與Channel一起使用)

通過關鍵字go來建立併發執行的Goroutine。
基本格式:go func()

import (
	"fmt"
	"math/rand"
)
func Test(ch chan int){
	ch <- rand.Int()  //隨機數獲取並寫入
	fmt.Println("Test")
}

func main() {
	chs := make([]chan int , 10) //定義一個包含10個Channel的陣列chs
	for i:=0;i<10;i++{
		chs[i] = make(chan int)
		go Test(chs[i]) //啟動10個Goroutine,對應每一個Goroutin分配一個Channel
	}
	for _,ch := range chs{
		value := <-ch     //從通道讀取資料
		fmt.Println(value)
	}
	fmt.Println("main")  //因為通道的寫入和讀取都是阻塞的,從而保證了即使沒有鎖,所有的Goroutin執行完後才main才返回。即:main總是在最後輸出的。
}

③通道(Channel)

1>概念

是Go提供的訊息通訊機制。主要用於併發通訊,類似於單雙向資料管道(Pipe),使用者可以通過Channel在兩個或多個Goroutine之間傳遞訊息。

注意:

  1. 同一時刻只有一個Goroutine能從Channel中接收資料,這就避免了互斥鎖的問題。
  2. Channel中資料的傳送和接收都是原語操作,不會中斷,只會失敗。

2>宣告和初始化

Channel是引用型別,一個Channel只能傳遞一種型別的值,這個型別需要在宣告Channel時指定。
支援的型別:基本型別、指標、Array、Slice、Map

var chanName chan ElementType
var ch chan int   //一個傳遞int型別的Channel。chan為關鍵字。
ch := make(chan int)   //用make函式直接宣告

3>資料接收和傳送

ch < - value      //通道接收資料。ch表示通道,value表示資料。
value = < - ch  //通道傳送資料

注意:
3. 向Channel寫入資料通常會導致程式阻塞,直到有其他Goroutine從這個Channel中讀取資料。
4. 如果Channel中之前沒有寫入資料,那麼從Channel中讀取資料也會導致阻塞,直到Channel中被寫入資料為止。

4>close()

  1. 只有傳送端才能關閉Channel,只有接收端才能獲得關閉狀態。
  2. close()呼叫不是必須的,但如果接收端使用range或者迴圈接收資料,就必須呼叫close(),否則報錯:throw : all goroutines are asleep-deadlock!

5>單向通道

宣告時可以將Chanel制定為單向通道:只能接收或只能傳送。

var chanName chan <- ElementType  //只能接收
var chanName <- chan ElementType //只能傳送

6>非同步通道

給Channel設定一個Buffer值,用於持續傳輸大量資料。
在Buffer未寫滿之前,不阻塞傳送操作(即使沒有讀取方,傳送方也不斷寫入資料);
在Buffer未讀完之前,不阻塞接收操作。

ch := make(chan int, 1024) //建立一個大小為1024的int型別Channel。

7>select機制

主要用於解決通道通訊中的多路複用問題。

select語句(類似switch):

select{
	case <- chan1:   //如果 chan1 成功讀取資料,則進行該case處理語句
	case <- chan2:  
	……
	default:
}

select直接檢測case語句,每個case語句必須是一個面向Channel的操作.
只要其中一個case完成,程式就會繼續向下執行。利用這個特性可以可以為Channe實現超時處理功能。

8>超時機制

由於通道的接收是阻塞式的,為了將阻塞式的通訊轉換為非阻塞式,將select機制和超時機制配合使用,以提高系統通訊效率。
在Go語言併發程式設計的通訊過程中,所有錯誤處理都由超時機制來完成。
超時機制一般用來解決通訊死鎖,通常設定一個超時引數,通訊雙方如果在設定的時間內仍然沒處理完成任務,則該處理過程會立即被終止,並返回對應的超時資訊。
Go沒有提供直接的超時處理機制。利用select機制可以實現。

3)網路程式設計

傳統的Socket網路程式設計分為:流式套接字(基於TCP)、資料包套接字(基於UDP)、原始式套接字(基於IP)。

①Dial()

Go語言對socket進行了封裝,無論期望用什麼協議都只需要呼叫Dial函式即可。
支援網路協議:tcp、tcp4、tcp6、udp、udp4、udp6、ip、ip4、ip6。
建立連線:

func Dial ( net, addr string) (Conn, error)  //net是網路協議名,addr是IP地址或域名,後面可跟隨埠號。
conn,err := net.Dial ("tcp", "192.168.0.1:5000")
conn,err := net.Dial ("ip4:icmp", "www.baidu.com")

傳送資料:使用conn物件的Write()方法
接收資料:使用conn物件的Read()方法

相關文章