定义
First Class Function 是一种编程语言的术语, 指当一个函数可以赋值给变量, 可以当作参数传参, 可以作为返回值返回时, 称为First Class Function. 而Go语言拥有First Class Function特性;
解释
这一部分将结合Go语言语法与各种使用场景阐述First Class Function;
Scenario 1: Anonymous function
Anonymous function (匿名函数)指的是没有函数名称的函数, 其在项目中往往充当简单的功能函数, 其使用方式很灵活, 例如:
赋值
Anonymous function给某变量;1
2
3
4
5
6
7
8
9
10
11
12
13package main
import (
"fmt"
)
func main() {
a := func() {
fmt.Println("Hello First Class Function")
}
a()
fmt.Printf("Type of variable a is %T", a)
}输出为:
1
2Hello First Class Function
Type of variable a is func()上面定义了一个
Anonymous function,其会输出Hello First Class Function,并赋值给a;
随后调用a, 并打印出了a的类型, 发现其为func();Anonymous function创建的同时运行;1
2
3
4
5
6
7
8
9
10
11
12package main
import (
"fmt"
)
func main() {
func() {
fmt.Println("Hello First Class Function")
}()
}输出:
1
Hello First Class Function
对于
Anonymous function也可以不赋值, 例如上面定义了Anonymous function的同时立马运行, 输出了Hello First Class Function;Anonymous function也支持传参;1
2
3
4
5
6
7
8
9
10
11package main
import (
"fmt"
)
func main() {
func(n string) {
fmt.Println("Hello", n)
}("Gophers")
}对于
Anonymous function, 自然也可以像普通函数一样通过传参的方式使用; 例如上面定义了一个接受string入参的Anonymous function.
Scenario 2: User defined function types
Go 语言支持用户自定义函数类型, 例如:
1 | package main |
输出:
1 | Min 5 |
上面定义了一个自定义函数类型Min, 随后通过Anonymous function的方式赋值给Min类型的变量m; 随后调用函数m获得两数中的小数;
Scenario 3: Higher-order functions
Higher-order functions 高维函数指的是符合以下两者之一的函数:
- 函数传参: 入参中至少包含一个函数入参
- 返回函数: 返回值中包含有函数
函数传参:
1 | package main |
输出:
1 | Func result: 5 |
上面的例子中, 我定义了一个higher高维函数, 其接受一个函数入参f, 并在内部逻辑中输出f(5, 6)的结果; 在main函数中, 定义了一个Anonymous function 并赋值给变量min; 最后将min传递给higher函数执行.
返回函数:
1 | package main |
输出为:
1 | Result is: 5 |
在上面的例子中, 我定义了一个higher高维函数, 其会返回一个实现了Min逻辑的函数; 在main函数中, 我通过变量f接收了higher的返回值, 并在最后输出f的执行结果;
Scenario 4: Closures
Closures 闭包是anonymous functions的特殊用例, 指的是在Function Body 内使用了外部的变量, 导致外部变量在函数使用期间无法被GC回收;例如:
1 | package main |
输出为:
1 | Hello World |
在上面的例子中appendStr函数返回了一个closure, 其绑定了变量t; 在main函数中将closure赋值给变量a, 并在随后调用了两次; 可以发现, 第二次调用时的输出为Hello World Gopher而不是Hello Gopher. 这说明变量t在closure使用过程中一直被引用, 并且其值会随着多次调用,产生无法预期的变化. 在项目中, 一般避免使用Closure, 以免产生不必要的误解;
用例
这一部分将通过一个简单的用例, 说明First Class Function的用于Dependency Injection的用例场景;
定义一个
student结构体:1
2
3
4
5
6type student struct {
firstName string
lastName string
grade string
country string
}student结构体中包含有学生基础信息,姓, 名, 分数, 国家;定义一个
filter函数:1
2
3
4
5
6
7
8
9func 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
}定义了一个过滤函数
filter, 其接受一个student列表与filter logic: f, 函数中会遍历student列表并返回符合f的学生列表;
定义了一个过滤函数filter, 其接受一个student列表与filter logic: f, 函数中会遍历student列表并返回符合f的学生列表;
函数主逻辑如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54package 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 studentList() []student {
s1 := student{
firstName: "Naveen",
lastName: "Ramanathan",
grade: "A",
country: "India",
}
s2 := student{
firstName: "Samuel",
lastName: "Johnson",
grade: "B",
country: "USA",
}
s3 := student{
firstName: "Sun",
lastName: "Qingzhi",
grade: "C",
country: "China",
}
return []student{s1, s2, s3}
}
func main() {
s := studentList()
f := filter(s, func(s student) bool {
if s.grade == "C" {
return true
}
return false
})
fmt.Println(f)
}在
main函数逻辑中, 首先通过studentList函数获得了初始化学生列表, 随后通过调用filter函数, 并注入了一个匿名函数1
2
3
4
5
6
7// 找到成绩为C的学生
func(s student) bool {
if s.grade == "C" {
return true
}
return false
}随后获得了符合匿名函数的学生列表;
输出为:
1
[{Sun Qingzhi C China}]
这么做的好处在于将
filter logic与Caller拆分开来, 是一种松耦合的编码方式;如果发现目前有业务调整, 需要得到来自于
India的学生列表, 那么只需要将filter logic逻辑更换为:1
2
3
4
5
6
7// 找到来自于印度的学生
func(s student) bool {
if s.country == "India" {
return true
}
return false
}输出为:
1
[{Naveen Ramanathan A India}]
总结
本文介绍的核心为First Class Function, 分别介绍了定义, Go中的使用场景与用例实战. 相信认真读到这里, 可以发现First Class Function是一个简单的术语, 在项目中或多或少的都有涉及. 期望这一篇文章可以对你有所帮助;