Go基礎系列:函數(2)——回調函數和閉包

回調函數與閉包

當函數具備以下兩種特性的時候,就可以稱之爲高階函數:

  • 函數可以作爲另一個函數的參數(典型用法是回調函數)
  • 函數可以返回另一個函數,即讓另一個函數作爲這個函數的返回值(典型用法是閉包)

一般來說,附帶的還具備一個特性:函數可以作爲一個值賦給變量:

f := func(){...}
f()

由於go中函數不能嵌套函數,所以函數返回函數的時候,就只能返回匿名函數。

高階函數示例

例如:將函數作爲空一格函數的參數,

package main

import "fmt"

func added(msg string, a func(a, b int) int) {
    fmt.Println(msg, ":", a(33, 44))
}

func main() {
    // 函數內部不能嵌套命名函數
    // 所以main()中只能定義匿名函數
    f := func(a, b int) int {
        return a + b
    }
    added("a+b", f)
}

以下示例是函數返回另一個函數:

package main

import "fmt"

func added() func(a, b int) int {
    f := func(a, b int) int {
        return a + b
    }
    return f
}

func main() {
    m := added()
    fmt.Println(m(33, 44))
}

回調函數(sort.SliceStable)

將函數B作爲另一個函數A的參數,可以使得函數A的通用性更強,可以隨意定義函數B,只要滿足規則,函數A都可以去處理,這比較適合於回調函數。

在Go的sort包中有一個很強大的Slice排序工具SliceStable(),它就是將排序函數作爲參數的:

func SliceStable(slice interface{}, less func(i, j int) bool)

這個函數是什麼意思呢?給定一個名爲slice的Slice結構,使用名爲less的函數去對這個slice排序。這個less函數的結構爲less func(i, j int) bool,其中i和j指定排序依據。Go中已經內置好了排序的算法,我們無需自己去定義排序算法,Go會自動從Slice中每次取兩個i和j索引對應的元素,然後去回調排序函數less。所以我們只需要傳遞升序還是降序、根據什麼排序就可以。

package main

import (
    "fmt"
    "sort"
)

func main() {
    s1 := []int{112, 22, 52, 32, 12}
    // 定義排序函數
    less := func(i, j int) bool {
        // 降序排序
        return s1[i] > s1[j]
        // 升序排序:s1[i] < s1[j]
    }
    //
    sort.SliceStable(s1, less)
    fmt.Println(s1)
}

這裏的排序函數就是回調函數。每取一次i和j對應的元素,就調用一次less函數。

可以將排序函數直接寫在SliceStable()的參數位置:

sort.SliceStable(s1, func(i, j int) bool {
    return s1[i] > s1[j]
})

還可以更強大更靈活。例如,按照字符大小順序來比較,而不是按照數值大小比較:

package main

import (
    "fmt"
    "sort"
    "strconv"
)

func main() {
    s1 := []int{112, 220, 52, 32, 42}
    sort.SliceStable(s1, func(i, j int) bool {
        // 將i和j對應的元素值轉換成字符串
        bi := strconv.FormatInt(int64(s1[i]), 10)
        bj := strconv.FormatInt(int64(s1[j]), 10)
        // 按字符順序降序排序
        return bi > bj
    })
    fmt.Println(s1)
}

按照字符串長度來比較:

package main

import (
    "fmt"
    "sort"
)

func main() {
    s1 := []string{"hello","malong","gaoxiao"}
    sort.SliceStable(s1, func(i, j int) bool {
        // 按字節大小順序降序排序
        return len(s1[i]) > len(s1[j])
    })
    fmt.Println(s1)
}

更嚴格地說是按字節數比較,因爲len()操作字符串時獲取的是字節數而非字符數。如果要按照字符數比較,則使用如下代碼:

package main

import (
    "fmt"
    "sort"
)

func main() {
    s1 := []string{"hello","世界","gaoxiao"}
    sort.SliceStable(s1, func(i, j int) bool {
        // 按字節大小順序降序排序
        return len([]rune(s1[i])) > len([]rune(s1[j]))
    })
    fmt.Println(s1)
}

閉包

待續

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章