什么是头等函数?
支持头等函数的编程语言,可以把函数赋值给变量,也可以把函数作为其它函数的参数或者返回值。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: