學習筆記-go入門2.0
阿新 • • 發佈:2021-08-11
go編譯型語言,so函式編寫的順序無關緊要。
goroutine 協程
Go語言裡面擁三種類型的函式:
-普通的帶有名字的函式
-匿名函式或者 lambda 函式
-方法
同一種類型返回值和帶有變數名的返回值
func name()(int,int){return a,b}
func name()(a , b int){return}
不可以:
func name()(a,b int,int){return}
定義函式變數:
var fname func()
匿名函式篇: ① 函式內部定義函式:閉包 好處:內聯在函式中,不需要宣告,可直接使用函式的變數 Go語言中閉包是引用了自由變數的函式,被引用的自由變數和函式一同存在,即使已經離開了自由變數的環境也不會被釋放或者刪除,在閉包中可以繼續使用這個自由變數 函式 + 引用環境 = 閉包 一個函式型別就像結構體一樣,可以被例項化,函式本身不儲存任何資訊,只有與引用環境結合後形成的閉包才具有“記憶性”,函式是編譯期靜態的概念,而閉包是執行期動態的概念。 閉包(Closure)在某些程式語言中也被稱為 Lambda 表示式。 閉包對環境中變數的引用過程也可以被稱為“捕獲”,在 C++11 標準中,捕獲有兩種型別,分別是引用和複製,可以改變引用的原值叫做“引用捕獲”,捕獲的過程值被複制到閉包中使用叫做“複製捕獲”。 // C++ 與 C# 中為閉包建立了一個類,而被捕獲的變數在編譯時放到類中的成員中,閉包在訪問被捕獲的變數時,實際上訪問的是閉包隱藏類的成員。 在閉包內部修改引用的變數 閉包對它作用域上部的變數可以進行修改,修改引用的變數會對變數進行實際修改,通過下面的例子來理解: 例子: // 準備一個字串 str := "hello world" // 建立一個匿名函式 foo := func() { // 匿名函式中訪問str str = "hello dude" } // 呼叫匿名函式 foo() 被捕獲到閉包中的變數讓閉包本身擁有了記憶效應,閉包中的邏輯可以修改閉包捕獲的變數,變數會跟隨閉包生命期一直存在,閉包本身就如同變數一樣擁有了記憶效應。 ② 函式內部呼叫其他函式:函式呼叫 ③ 函式內部呼叫引數傳過來的函式:回撥函式 將一個函式的指標作為引數傳遞給另一個函式,在外部再定義這個函式的實現。 回撥函式例子: func visit(list []int, f func(int)) { for _, v := range list { f(v) } } func main() { // 使用匿名函式列印切片內容,可改變傳入函式的實現 visit([]int{1, 2, 3, 4}, func(v int) { fmt.Println(v) }) } ④ 函式內部呼叫自己這個函式:遞迴
go介面篇: 定義介面: type Invoker interface { // 需要實現一個Call方法 Call(interface{}) //這個傳參?? } 1.結構體實現介面 type Struct struct { } // 實現Invoker的Call func (s *Struct) Call(p interface{}) { fmt.Println("from struct", p) } main函式中: // 宣告介面變數 var invoker Invoker // 例項化結構體 s := new(Struct) // 將例項化的結構體賦值到介面 invoker = s // 使用介面呼叫例項化結構體的方法Struct.Call invoker.Call("hello") 2.函式體實現介面 函式的宣告不能直接實現介面,需要將函式定義為型別後,使用型別實現結構體,當型別方法被呼叫時,還需要呼叫函式本體。 // 函式定義為型別 type FuncCaller func(interface{}) // 實現Invoker的Call func (f FuncCaller) Call(p interface{}) { // 呼叫f()函式本體 f(p) } main函式中: // 宣告介面變數 var invoker Invoker // 將匿名函式轉為FuncCaller型別, 再賦值給介面 invoker = FuncCaller(func(v interface{}) { fmt.Println("from function", v) }) // 使用介面呼叫FuncCaller.Call, 內部會呼叫函式本體 invoker.Call("hello")
TODO:標記部分程式碼以供將來參考:優化和改進的領域、可能的更改、要討論的問題等。
Go語言goroutine和channel使用
goroutine是Go語言中的輕量級執行緒實現,由Go語言執行時(runtime)管理。使用的時候在函式前面加“go”這個單詞作為關鍵詞,也是與普通函式的區別了。在函式前面加go關鍵字就可以建立一個新的goroutine進行併發執行。
channel是Go語言提供的goroutine間的通訊方式,我們可以使用channel在兩個或多個goroutine之家傳遞訊息。channel使用的關鍵字是用“chan”.
go方法: go語言中函式的概念和c語言中的函式類似,函式名其實是一個指標,而go語言的方法是擁有接收者的函式,其實是c++中類的方法的概念。函式是獨立存在的,而方法必須有接收者,即必須依附於某個物件。go語言使用struct來抽象物件。因此方法的接收者可以是struct例項或struct的指標。 type user struct { name string, email string, } //這是函式的定義 func notify(email string) { fmt.Println("Email is %s", email) } //這是方法的定義 func (u user) notify(email string) { fmt.Println("Email is %d", email) }
go error型別:
見go入門。
對方法的接收者傳值:不改變接收者。傳地址才改變。
defer:
Go語言的 defer 語句會將其後面跟隨的語句進行延遲處理,在 defer 歸屬的函式即將返回時,將延遲處理的語句按 defer 的逆序進行執行,也就是說,先被 defer 的語句最後被執行,最後被 defer 的語句,最先被執行。
當有多個 defer 行為被註冊時,它們會以逆序執行(類似棧,即後進先出)
defer func(){ }
go func(){ }
go中{}後的():