编程语言支持头等函数是指:允许函数作为类型可以赋值给变量,作为参数传递给其他函数,从其他函数返回。Go语言支持头等函数。
这一节我们将导论头等函数的语法和各种使用案例。
匿名函数让我们一个简单例子开始:将函数赋值给一个变量。
package main
import (
"fmt"
)
func main() {
a := func() {
fmt.Println("hello world first class function")
}
a()
fmt.Printf("%T", a)
}
在上述代码中,我们将一个函数赋值给变量a(第8行)。只就是将函数赋值给变量的语法。仔细观察的话可以发现,赋值给变量的函数没有名字。这种没有名字的函数,我们称之为匿名函数(anonymous functions).
唯一调用这个函数的方法是使用变量a。我们通过a()来调用这个函数,函数打印hello world first class function。在第12行,我们打印变量a的类型。结果打印func()
程序执行结果:
hello world first class function
func()
不用赋值给变量的也可以调用匿名函数的。让我们来看看这个是如何实现的:
package main
import (
"fmt"
)
func main() {
func() {
fmt.Println("hello world first class function")
}()
}
在上述代码中,一个字符创作为参数传递给匿名函数(第10行),程序执行结果:
Welcome Gophers
用户自定义函数类型
就像我么你自定义结构体类型一样,我们也可以自定义函数类型。
type add func(a int, b int) int
上述代码片段新建一个函数类型add:接收2个整型参数并返回一个整型。现在我们可以定义add类型变量。
看看下面这个例子:
package main
import (
"fmt"
)
type add func(a int, b int) int
func main() {
var a add = func(a int, b int) int {
return a + b
}
s := a(5, 6)
fmt.Println("Sum", s)
}
在上述代码中,第10行,我们定义了一个自定义add类型的变量a,并将一个函数签名符合add类型的函数赋值给变量a。程序在第13行调用这个函数,返回值赋值给变量s。程序执行结果:
Sum 11
高阶函数
高阶函数必须具备以下条件之一:
- 拥有一个或多个参数
- 函数作为返回值
针对上述两种情况,我们看看一些简单实例。
把函数当做参数传递给其他函数package main
import (
"fmt"
)
func simple(a func(a, b int) int) {
fmt.Println(a(60, 7))
}
func main() {
f := func(a, b int) int {
return a + b
}
simple(f)
}
上述例子,我们定义了函数simple(第7行),它的参数是一个带有2个整型参数,并且返回值为整型的函数变量。在主函数中第12行,我们新建一个匿名函数,该函数的签名符合simple的函数签名。接下来给simple函数传递这个函数变量f并调用执行。程序执行结果是67.
在其它函数中返回一个函数下面我们重写上述代码,实现从simple函数返回一个函数:
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))
}
上述程序,simple函数返回一个函数签名为2个整型参数和返回值为整型的函数。
simple函数在主函数15行调用。函数返回值赋值给变量s。现在s拥有从simple函数返回的函数。给s传递两个整型参数并调用,程序执行结果为67.
闭包闭包是匿名函数的一个特例。当一个匿名函数所访问的变量定义在函数体的外部时,就称这样的匿名函数为闭包。
看个示例更好理解:
package main
import (
"fmt"
)
func main() {
a := 5
func() {
fmt.Println("a =", a)
}()
}
上述代码中,匿名函数访问的变量a是在函数体外定义的(在第10)。因此该匿名函数是一个闭包。
每一个闭包都会绑定一个它自己的外围变量(Surrounding Variable)。我们通过一个简单示例来体会这句话的含义。
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 := appendStr()
b := appendStr()
fmt.Println(a("World"))
fmt.Println(b("Everyone"))
fmt.Println(a("Gopher"))
fmt.Println(b("!"))
}
在上述程序中,函数appendStr返回一个闭包。这个闭包的外围变量是t。我们来理解这是什么意思。
在第 17 行和第 18 行声明的变量 a 和 b都是闭包,它们绑定了各自的 t值。
a
bbtbtHellobtEveryone
该程序会输出:
Hello World
Hello Everyone
Hello World Gopher
Hello Everyone !
头等函数的应用
迄今为止,我们已经定义了什么是头等函数,也看了一些专门设计的示例,来学习它们如何工作。现在我们来编写一些实际的程序,来展现头等函数的实际用处。
students
student
type student struct {
firstName string
lastName string
grade string
country string
}
filterstudents
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
}
filterstudentboolstudentftruermain
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}
f := filter(s, func(s student) bool {
if s.grade == "B" {
return true
}
return false
})
fmt.Println(f)
}
mains1s2sBBtruefilter
[{Samuel Johnson B USA}]
filter
实现它的代码如下所示:
c := filter(s, func(s student) bool {
if s.country == "India" {
return true
}
return false
})
fmt.Println(c)
main
map
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]
现在简单概括一下本教程讨论的内容:
- 什么是头等函数?
- 匿名函数
- 用户自定义的函数类型
- 高阶函数
- 把函数作为参数,传递给其它函数
- 在其它函数中返回函数
- 闭包
- 头等函数的实际用途
本节课程到此结束。祝您愉快。
ps:新手翻译,欢迎大家指正!