在 Go 语言中,我们可以把函数作为一种变量,用 type 去定义它,那么这个函数类型就可以作为值传递,甚至可以实现方法,这一特性实在太灵活了,有时候我们甚至可以利用这一特性进行类型转换。
作为值传递的条件是类型具有相同的参数以及相同的返回值。
函数签名
什么是函数签名
函数类型 又叫 函数签名 , 一个函数的类型就是函数定义首行去掉函数名、参数名和{,可以 使用 fmt.Printf 的”%T”格式化参数打印函数的类型。
什么是函数类型相同
两个函数类型相同的条件是:
拥有相同的形参列表和返回值列表(列表元素的次序、个数和类型都相同),形参名可以不同 。
以下 3 个函数的函数类型完全一样。
1
2
3
|
func add (a , b int) int { return a + b }
func sub (c int, d int) int { return c - d }
func mul (e int, f int) int { return e * f }
|
举例:
新建test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
|
package main
import "fmt"
func add(a, b int) int { return a + b }
func sub(c int, d int) int { return c - d }
func mul(e int, f int) int { return e * f }
func main() {
fmt.Printf("%T\n", add)
fmt.Printf("%T\n", sub)
fmt.Printf("%T\n", mul)
}
|
执行结果:
1
2
3
|
func(int, int) int
func(int, int) int
func(int, int) int
|
通过Type定义函数类型
搞明白了什么是函数类型相同之后,接下来了解通过Type定义函数类型。
通过 type 可以定义函数类型,格式如下
|
type typeName func(arguments) retType
|
函数类型也是一种类型,故可以将其定义为函数入参,在 go 语言中函数名可以看做是函数类型的常量,所以我们可以直接将函数名作为参数传入的函数中。
例如:
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
|
package main
import "fmt"
func add(a, b int) int {
return a + b
}
//sub作为函数名可以看成是 op 类型的常量
func sub(a, b int) int {
return a - b
}
// ***************************
// 定义函数类型 op
// ***************************
type op func(a, b int) int
// ***************************
// 形参指定传入参数为函数类型op
// ***************************
func Oper(fu op, a, b int) int {
return fu(a, b)
}
func main() {
//在go语言中函数名可以看做是函数类型的常量,所以我们可以直接将函数名作为参数传入的函数中。
aa := Oper(add, 1, 2)
fmt.Println(aa)
bb := Oper(sub, 1, 2)
fmt.Println(bb)
}
|
函数的类型转换
Go 语言的类型转换基本格式如下:
1
2
|
// 类型转换
type_name(expression)
|
举个例子:
本例声明了一个 CalculateType 函数类型,并实现 Serve() 方法,并将拥有相同参数的 add 和 mul 强制转换成 CalculateType 函数类型,同时这两个函数都拥有了 CalculateType 函数类型的 Serve() 方法。
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
|
package main
import "fmt"
// 声明了一个函数类型
type CalculateType func(int, int)
// 该函数类型 CalculateType 实现了一个方法
func (c *CalculateType) Serve() {
fmt.Println("我是一个函数类型")
}
// 加法函数
func add2(a, b int) {
fmt.Println(a + b)
}
// 乘法函数
func mul2(a, b int) {
fmt.Println(a * b)
}
func main() {
a := CalculateType(add2) // 将 add2 函数强制转换成 CalculateType 类型
b := CalculateType(mul2) // 将 mul2 函数强制转换成 CalculateType 类型
a(2, 3) // 5
b(2, 3) // 6
a.Serve() // 我是一个函数类型
b.Serve() // 我是一个函数类型
}
|
函数作参数传递
如下示例,Calculate 的 f 参数类型为 CalculateType,add 和 mul 函数具有和 CalculateType 函数类型相同的参数和返回值,因此可以将 add 和 mul 函数作为参数传入 Calculate 函数中。
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
|
package main
import "fmt"
// 函数作为参数传递
type CalculateType3 func(a, b int) int // 声明了一个函数类型
// 加法函数
func add3(a, b int) int {
return a + b
}
// 乘法函数
func mul3(a, b int) int {
return a * b
}
func Calculate3(a, b int, f CalculateType3) int {
return f(a, b)
}
func main() {
a, b := 2, 3
fmt.Println(Calculate3(a, b, add3)) // 5
fmt.Println(Calculate3(a, b, mul3)) // 6
}
|
net/http 包源码例子
http.HandleFunc()是一个注册函数,传一个string类型的路由,和一个函数,函数的参数为**(http.ResponseWriter, *http.Request)**。
跟踪进入函数,在 golang 源码 net/http/server.go 文件中
1
2
3
4
5
6
7
|
// HandleFunc registers the handler function for the given pattern
// in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
|
在 HandleFunc 中调用了 DefaultServeMux.HandleFunc(pattern, handler)
1
2
3
4
5
6
7
|
// HandleFunc registers the handler function for the given pattern.
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
// 将传入的函数 handler 强制转换成 HandlerFunc
// 本示例是 sayHi 函数
mux.Handle(pattern, HandlerFunc(handler))
}
|
1
2
3
4
5
6
7
8
9
|
// 定义函数类型
type HandlerFunc func(ResponseWriter, *Request)
// 函数类型的方法
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
|
HandlerFunc 实现了 Handler 接口
Handler接口定义:
1
2
3
|
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
|
这段源码的目的是为了将我们自定义的 Handler 强制实现 ServeHTTP() 方法,如下例子:
1
2
3
4
5
6
7
8
9
10
11
12
|
// 自定义函数
// 函数类型是 HandlerFunc
func sayHi(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "hi")
}
func main() {
// (2)
http.HandlerFunc("/", sayHi)
http.ListenAndserve(":8080", nil)
}
|
因为 HandlerFunc 是一个函数类型,而 sayHi 函数拥有和 HandlerFunc 函数类型一样的参数值,因此可以将 sayHi 强制转换成 HandlerFunc,因此 sayHi 也拥有了 ServeHTTP() 方法,也就实现了 Handler 接口,同时,HandlerFunc 的 ServeHTTP 方法执行了它自己本身,也就是 sayHi 函数,这也就可以看出来了,sayHi 就是 Handler 被调用之后的执行结果。
原文地址:http://www.manoner.com/post/GoLand/Go%E5%87%BD%E6%95%B0%E4%BD%9C%E4%B8%BA%E5%80%BC%E4%B8%8E%E7%B1%BB%E5%9E%8B/
|