Go学习笔记15-头等函数

什么是头等函数?

支持头等函数的编程语言,可以把函数赋值给变量,也可以把函数作为其它函数的参数或者返回值。Go语言支持头等函数的机制。

匿名函数

package main

import "fmt"

func main() {
    // 把函数赋值给一个变量
    // 赋值给a的函数没有名称,这类函数称为匿名函数
    a := func() {
        fmt.Println("hello world first class function")
    }
    a() // hello world first class function
    fmt.Printf("%T", a) // func()

    // 要调用一个匿名函数,可以不用赋值给变量
    func() {
        fmt.Println("hello world first class function")
    }() // hello world first class function

    // 与其它函数一样,可以向匿名函数传递参数
    func(n string) {
        fmt.Println("Welcome", n)
    }("Gopher") // Welcome Gopher
}

用户自定义的函数类型

正如我们定义自己的结构体类型一样,也可以定义自己的函数类型。

package main

import "fmt"

type add func(a int, b int) int // 定义新的函数类型add

func main() {
    var a add = func(a int, b int) int {
        return a + b
    }
    s := a(5, 6)
    fmt.Println("Sum", s) // Sum 11
}

高阶函数

满足下列条件之一的函数称为高阶函数:

  • 接收一个或多个函数作为参数
  • 返回值是一个函数

1. 把函数作为参数,传递给其它函数

package main

import "fmt"

// simple接收一个函数参数
func simple(a func(a, b int) int) {
    fmt.Println(a(60, 7))
}

func main() {
    // 创建一个匿名函数f,其签名符合simple函数的参数
    f := func(a, b int) int {
        return a + b
    }
    simple(f) // 67
}

2. 在其它函数中返回函数

package main

import "fmt"

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

func main() {
    s := simple()
    fmt.Println(s(60, 7)) // 67
}

闭包

闭包(Closure)是匿名函数的一个特例。当一个匿名函数所访问的变量定义在函数体的外部时,就称这样的匿名函数为闭包

package main

import "fmt"

func main() {
    a := 5
    // 函数内访问了变量a,而a存在于函数体外部,因此这个匿名函数就是闭包
    func() {
        fmt.Println("a =", a)
    }() // a = 5
}

每一个闭包都会绑定一个它自己的外围变量,通过下面的例子体会:

package main

import "fmt"

func appendStr() func(string) string {
    t := "Hello"
    c := func(b string) string {
        t = t + " " + b
        return t
    }
    return c
}

func main() {
    // 变量a和b都是闭包,它们绑定了各自的t值
    a := appendStr()
    b := appendStr()
    fmt.Println(a("World"))    // "Hello World"
    fmt.Println(b("Everyone")) // "Hello Everyone"

    fmt.Println(a("Gopher")) // "Hello World Gopher"
    fmt.Println(b("!"))      // "Hello Everyone !"
}

头等函数的实际用途

例子1:基于一些条件,来过滤一个students切片。

package main

import "fmt"

type student struct {
    firstName string
    lastName  string
    grade     string
    country   string
}

func filter(s []student, f func(student) bool) []student {
    var r []student
    for _, v := range s {
        if f(v) == true {
            r = append(r, v)
        }
    }
    return r
}

func main() {
    s1 := student{
        firstName: "Naveen",
        lastName:  "Ramanathan",
        grade:     "A",
        country:   "India",
    }
    s2 := student{
        firstName: "Samuel",
        lastName:  "Johnson",
        grade:     "B",
        country:   "USA",
    }
    s := []student{s1, s2}
    // 假如我们想要查找所有来自印度的学生,通过修改传递给filter的函数参数,就很容易实现了
    f := filter(s, func(s student) bool {
        if s.grade == "B" {
            return true
        }
        return false
    })
    fmt.Println(f) // [{Samuel Johnson B USA}]
}

例子2:下面的程序会对切片的每个元素执行相同的操作,并返回结果。

package main

import "fmt"

func iMap(s []int, f func(int) int) []int {
    var r []int
    for _, v := range s {
        r = append(r, f(v))
    }
    return r
}

func main() {
    a := []int{5, 6, 7, 8, 9}
    r := iMap(a, func(n int) int {
        return n * 5
    })
    fmt.Println(r) // [25 30 35 40 45]
}

reference:

https://studygolang.com/articles/12789