Richard's Blog

Golang学习笔记——定义函数类型实现接口

字数统计: 739阅读时长: 3 min
2019/05/01 Share

今天在看golang的教程中解释当我们使用golang创建http服务时的内部原理。

golang创建http服务代码如下

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
package main

import (
"fmt"
"net/http"
)

func sayHelloName(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
fmt.Println(r.Form)
fmt.Println("Path: ", r.URL.Path)
fmt.Println("Scheme: ", r.URL.Scheme)
fmt.Println(r.Form["url_long"])
for k, v := range r.Form {
fmt.Println("key:", k)
fmt.Println("value:", v)
}
fmt.Fprintf(w, "Hello astaixe!")
}

func main() {
http.HandleFunc("/", sayHelloName)
err := http.ListenAndServe(":9090", nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}

文章中解释了Handler接口,并表示我们所写的sayHelloName方法之所以能被当成Handler接口的实现是因为在包中定义了HandlerFunc

1
2
3
4
5
6
type HandlerFunc func(ResponseWriter, *Request)

// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}

看到这部分其实我是一脸蒙圈的,示例代码中HandleFunc方法的具体定义和实现没有在文章中给出,也没有说如何使用HandlerFunc把一个方法转换为Handler接口的实现。

经过一段时间的研究http包,其实如果在文章中给出HandleFunc方法和ServeMux.HandleFunc方法的实现会比较容易理解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 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 registers the handler function for the given pattern.
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
if handler == nil {
panic("http: nil handler")
}
mux.Handle(pattern, HandlerFunc(handler))
}

以上代码可以看出HandleFunc的第二个参数其实是一个方法,然后在代码中用HandlerFunc(handler)handler参数类型转换为HandlerFunc类型,而HandlerFunc类型实现了Handler接口,这样就可以让用户自定义一个方法的实现,实际在内部是一个接口。

以下是我找到的一个定义函数类型的列子

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
package main

import (
"fmt"
)

//定义接口
type adder interface {
add(string) int
}

//定义函数类型
type handler func(name string) int

//实现函数类型方法
func (h handler) add(name string) int {
return h(name) + 10
}

//函数参数类型接受实现了adder接口的对象(函数或结构体)
func process(a adder) {
fmt.Println("process:", a.add("taozs"))
}

//另一个函数定义
func doubler(name string) int {
return len(name) * 2
}

//非函数类型
type myint int

//实现了adder接口
func (i myint) add(name string) int {
return len(name) + int(i)
}

func main() {
//注意要成为函数对象必须显式定义handler类型
var my handler = func(name string) int {
return len(name)
}

//以下是函数或函数方法的调用
fmt.Println(my("taozs")) //调用函数
fmt.Println(my.add("taozs")) //调用函数对象的方法
fmt.Println(handler(doubler).add("taozs")) //doubler函数显式转换成handler函数对象然后调用对象的add方法
//以下是针对接口adder的调用
process(my) //process函数需要adder接口类型参数
process(handler(doubler)) //因为process接受的参数类型是handler,所以这儿要强制转换
process(myint(8)) //实现adder接口不仅可以是函数也可以是结构体

}
CATALOG