本文記錄了我在學習Go的過程時的一些筆記,主要是比較Python和Go之間的差別並做簡單描述,以此使Python程序員對Go語言的特性有簡略的瞭解。初學不免有紕漏,歡迎各位批評指正補充交流,謝謝。程序員
Go中的數組須要在建立時肯定長度,一個更靈活的對象是slice,後者可使用append添加,二者的定義方式類似。數據庫
var StrArray [10]string //數組,長度爲10 var StrSlice []string //slice
slice能夠根據現有的數組(稱爲底層數組)建立,但對其的修改會致使底層數組的改變。編程
Go語言支持指針,用法和C同樣數組
結構體和Python中的Class類似,但在這一代碼段中只能定義類型的數據佈局,方法須要定義指定接收對象的函數(見「方法」)。多線程
type Point struct{ X int Y int }
在結構體中添加結構體成員會使變量的訪問變得麻煩,Go中能夠不帶名稱定義結構體成員稱爲匿名成員。併發
結合匿名成員以及方法對匿名成員的處理(包含某個結構體匿名成員的結構體能夠接收該結構體的方法),匿名成員機制能夠視爲繼承app
type ColoredPoint struct { Point // 匿名成員 color string } var cp ColoredPoint cp.X = 1 cp.Y = 2 cp.color = "red"
不一樣於普通的函數,方法是指定接收對象的。iphone
包含某個結構體匿名成員的結構體能夠接收該結構體的方法。異步
隱式實現:知足接口所需的方法即爲實現某個接口,無需顯式聲明函數
type Phone interface { call()() text(str []string)(n int) }
當某一個類型擁有如上所屬的輸入和輸出的Write方法時,便可稱其實現了Writer接口。
type iPhone struct{} func (p iPhone) call (){ fmt.Println("call from iPhone") } func (p iPhone) text (str []string){ fmt.Println(str) fmt.Println("text from iPhone") return len(str) }
接口能夠被做爲一個變量定義,可被賦予具體類型。
var phone Phone // 賦值方法一 var iphone iPhone phone = iphone phone.call() phone.text("test") // 賦值方法二 phone = new(iPhone) phone.call() phone.text("test")
Go中每個併發的活動稱爲goroutine,不一樣於Python虛假的多線程或不穩定的多進程,goroutine被歸類爲協程(Coroutine)。
略
go f()
不一樣於Python會自動等待各Process運行結束後退出,在Go中main函數返回時,全部的goroutine都暴力地終結,可使用下文說起的通道阻塞或者sync的WaitGroup等待以保證各goroutine運行。
通道用於goroutine間的通訊,不一樣於Python的Threading庫或multiporcessing庫中的Queue(隊列),Go中的通道是須要標註數據類型的。
ch := make(chan int) //定義通道,int爲數據類型 ch <- x // 發送數據 x = <- ch // 接收數據 <- ch // 接收數據並丟棄 close(ch) //關閉通道
對通道的收發操做都是阻塞的。
不一樣於Queue關閉後沒法收發,通道關閉後沒法發送,但能夠接收剩餘的數據。
ch1 := make(chan int) ch2 := make(chan int, 0) // 二者含義相同
如上定義的通道,爲無緩衝通道,即一次不阻塞的發送後,數據被接收以前,第二次發送被阻塞。
ch := make(chan int, 3) //定義通道,int爲數據類型,容量爲3
如上定義的通道,能夠進行四次不阻塞的發送,第五次發送被阻塞(沒有接收的前提下)。
爲了不誤用能夠在函數的參數定義時固定通道的方向
func f(in <-chan int, out chan<- int) {}
如上定義時,通道in對於函數f來講是隻能接收的通道,通道out對於函數f來講是隻能發送的通道。
select的相似於switch,但不一樣的是select的分支上是阻塞着的操做而非數據。select使能夠同時等待多個操做的阻塞,直到某一個分支上的操做再也不阻塞。每一個select只執行一個分支。
select { case x1 <-ch1: // ... case x2 <-ch2: // ... case ch3 <- x3: // ... default: // ... }
一句任何涉及併發的編程都應該遵照的話:
‘‘Do not communicate by sharing memory; instead, share memory by communicating.’’
不要經過共享內存來通訊,應該用通訊來共享內存。即應當將對象限制在順序執行的環境下(好比某個協程中)進行寫操做。
也能夠用鎖。
相似multiprocessing.Lock有acquire()和release(),sync.Mutex有Lock()和Unlock()。(記得用defer延遲執行Unlock()以保證解鎖的執行)
Go提供共了一種更復雜的鎖,除了不可並行的寫鎖Lock()和Unlock(),還有可並行的讀鎖RLock()和RUnlock()。其使用相似於數據庫的2、三級封鎖協議。
延遲初始化,Once函數以某個函數爲參數,保證這個只須要執行一次的函數在並行狀況下執行且只執行一次。相同效果雖然用RWMutex也能夠實現但Once更加簡便
輸出一份包含全部數據競態的報告,go run/build/test時添加-race可使用該功能。
肯定須要使用的OS線程數目,能夠在做爲環境變量設置,或用函數runtime.GOMAXPROCS控制。
《Go程序設計語言》