Go語言學(xué)習(xí)筆記?。『瘮?shù)

函數(shù)

不支持 嵌套 (nested)、重載 (overload) 和 默認(rèn)參數(shù) (default parameter)。
? 無需聲明原型。
? 支持不定長變參。
? 支持多返回值。
? 支持命名返回參數(shù)。
? 支持匿名函數(shù)和閉包。
使用關(guān)鍵字 func 定義函數(shù),左大括號依舊不能另起一行。

func test(x,y int,s string) (int string) { //類型相同的相鄰參數(shù)可合并。
    n := x + y //多值返回必須用括號
    return n, fmt.Sprintf(s,n)
}

函數(shù)是第一類對象,可作為參數(shù)傳遞。建議將復(fù)雜簽名定義為函數(shù)類型,以便于閱讀。

func test(fn func() int) int {
    return fn()
}

type FormatFunc func(s string, x,y int) string //定義函數(shù)類型

func format(fn FormatFunc, s string, x,y int) string {
    return fn(s,x,y)
}

func main() {
    s1 := test(func() int { return 100}) //直接將匿名函數(shù)當(dāng)參數(shù)

    s2 := format(func(s string, x, y int) string {
        return fmt.Sprintf(s, x, y)
    }, "%d, %d", 10, 20)
    println(s1, s2)

變參

變參本質(zhì)上就是slice。只能有一個,且必須是最后一個參數(shù)位。

func test(s string, n ...int) string {
    var x int
    for _, i := range n {
        x += i
    }
    return fmt.Sprintf(s, x)
}

func main() {
    println(test("sum: %d", 1, 2, 3))
}

使用slice對象做變參時,必須展開。

func main() {
    s := []int{1, 2, 3}
    println(test("sum: %d",s...))
}

返回值

不能用容器對象接收多返回值。只能用多個變量,或“_”忽略。多個返回值可直接作為其他函數(shù)調(diào)用實參。

func test() (int, int) {
    return 1, 2
}

func add(x, y int) int {
    return x + y
}

func sum(n ...int) int {
    var x int
    for _, i := range n {
        x += i
    }
    return x
}

func main() {
    println(add(test()))
    println(sun(test()))
}

命名返回參數(shù)可看做與形參類似的局部變量,最后由 return 隱式返回。

func add(x, y int) (z int) {
    z = x + y
    return
}
func main() {
    println(add(1, 2))
}

命名返回參數(shù)可被同名局部變量遮蔽,此時需要顯式返回。

func add(x, y int) (z int) {
  {// 不能在一個級別,引發(fā) "z redeclared in this block" 錯誤。
      var z = x + y
      // return // Error: z is shadowed during return
      return z // 必須顯式返回。
  }
}

命名返回參數(shù)允許 defer 延遲調(diào)用通過閉包讀取和修改。

func add(x, y int) (z int) {
    defer func() {
        z += 100
    }()
    z = x + y
    return
}

func main() {
    println(add(1, 2)) //輸出:103
}

顯式 return 返回前,會先修改命名返回參數(shù)。

func add(x, y int) (z int) {
    defer func() {
        println(z)  //輸出:203
    }()

    z = x + y
    return z + 200
}

func main() {
    println(add(1, 2))  //輸出:203
}

匿名函數(shù)可賦值給變量,做為結(jié)構(gòu)字段,或者在 channel 里里傳送。閉包復(fù)制的是原對象指針,這就很容易解釋延遲引用現(xiàn)象。

延遲調(diào)用

關(guān)鍵字 defer 用于注冊延遲調(diào)用。這些調(diào)用直到 ret 前才被執(zhí)行,通常用于釋放資源或錯誤處理。多個 defer 注冊,按 FILO 次序執(zhí)行。哪怕函數(shù)或某個延遲調(diào)用發(fā)生錯誤,這些調(diào)用依舊會被執(zhí)行。

濫用 defer 可能會導(dǎo)致性能問題,尤其是在一個 "大循環(huán)" 里。

var log sync.Mutex
func test() {
    lock.Lock()
    lock.Unlock()
}
func testdefer() {
    lock.Lock()
    defer lock.Unlock()
}
func BenchmarkTest(b *testging.B) {
    for i := 0; i < b.N; i++ {
        test()
  }
}
func BenchmarkTestDefer(b *testging.B) {
    for i := 0; i < b.N; i++ {
        testdefer()
  }
}
//輸出:
BenchmarkTest    50000000  43 ns/op
BenchmarkTestDefer 20000000  128 ns/op

錯誤處理

沒有結(jié)構(gòu)化異常,使用panic拋出錯誤,recover捕獲錯誤。由于 panic、recover 參數(shù)類型為 interface{},因此可拋出任何類型對象。捕獲函數(shù) recover 只有在延遲調(diào)用內(nèi)直接調(diào)用才會終止錯誤,否則總是返回 nil。任何未
捕獲的錯誤都會沿調(diào)用堆棧向外傳遞。

func test() {
  defer func() {
        if err := recover(); err != nil {
            println(err.(string)) // 將interface{}轉(zhuǎn)型為string類型
    }()
    panic("panic erro!")
}

除用 panic 引發(fā)中斷性錯誤外,還可返回 error 類型錯誤對象來表示函數(shù)調(diào)用狀態(tài)。標(biāo)準(zhǔn)庫 errors.New 和 fmt.Errorf 函數(shù)用于創(chuàng)建實現(xiàn) error 接口的錯誤對象。通過判斷錯誤對象實例來確定具體錯誤類型。如何區(qū)別使用 panic 和 error 兩種方式?

慣例是:導(dǎo)致關(guān)鍵流程出現(xiàn)不可修復(fù)性錯誤的使用 panic,其他使用 error。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容