欢迎光临
我们一直在努力

golang中 type func() 用法分析

因看不懂 go 中的自定义函数类型,看了https://www.jianshu.com/p/431abe0d2ed5 理解了不少,特此搬运到自己博客

在看golang 的http服务部分代码时,被golang 中的 type func()写法难住了,一时没看懂代码。后来查资料后,有了一点理解。
在golang中可以通过这样简单实现一个http服务

package main

import "net/http"

func mHttp() {
    http.HandleFunc("/", h)
    http.ListenAndServe("0.0.0.0:8888",nil)
}
func h(w http.ResponseWriter, r *http.Request) {

}

http.HandleFunc()是一个注册函数,传一个string类型的路由,和一个函数,函数的参数为(http.ResponseWriter, *http.Request)。跟踪进入函数,在golang 源码net/http/server.go文件中

func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
    DefaultServeMux.HandleFunc(pattern, handler)
}

在HandleFunc调用了DefaultServeMux.HandleFunc(pattern, handler)
至于这些函数是干啥的先不做探讨,这不是本文的重点。
再次跟进函数

func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
    if handler == nil {
        panic("http: nil handler")
    }
    mux.Handle(pattern, HandlerFunc(handler))
}

在mux.Handle(pattern, HandlerFunc(handler)) 的第二个参数HandlerFunc(handler)是什么鬼。
跟进看一下

type HandlerFunc func(ResponseWriter, *Request)

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

原来HandlerFunc 是用 type 定义的函数,而函数的类型就是最开始传入的类型
func(ResponseWriter, *Request)
ServeHTTP是HandlerFunc的一个方法(注意一下,golang中方法和函数不是一回事)。并且HandlerFunc实现了 Handler接口
Handler接口定义:

type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}

回到HandleFunc方法中,mux.Handle(pattern, HandlerFunc(handler))的第二个参数是把传入的函数 handler 强转成 HandlerFunc类型,这样handler就实现了Handler接口。
到这我们明白HandlerFunc(handler)是把普通函数强转成type定义的函数。
现在写一个简单的demo验证一下:

package main
import "fmt"
type CalculateType func(int, int) // 声明了一个函数类型
// 该函数类型实现了一个方法
func (c CalculateType) Serve() {
	fmt.Println("我是一个函数类型")
}
// 加法函数
func add(a, b int) {
	fmt.Println(a + b)
}
// 乘法函数
func mul(a, b int) {
	fmt.Println(a * b)
}
func main() {
	a := CalculateType(add) // 将add函数强制转换成CalculateType类型
	b := CalculateType(mul) // 将mul函数强制转换成CalculateType类型
	a(2, 3)
	b(2, 3)
	a.Serve()
	b.Serve()
}
// 5
// 6
// 我是一个函数类型
// 我是一个函数类型

如上,声明了一个 CalculateType 函数类型,并实现 Serve() 方法,并将拥有相同参数的 add 和 mul 强制转换成 CalculateType 函数类型,同时这两个函数都拥有了 CalculateType 函数类型的 Serve() 方法。

可以改写成这样

package main
import "fmt"
type CalculateType func(int, int) // 声明了一个函数类型
// 该函数类型实现了一个方法
func (c CalculateType) Serve(a, b int) {
	c(a, b)
	fmt.Println("我是一个函数类型")
}
// 加法函数
func add(a, b int) {
	fmt.Println(a + b)
}
// 乘法函数
func mul(a, b int) {
	fmt.Println(a * b)
}
func main() {
	a := CalculateType(add) // 将add函数强制转换成CalculateType类型
	b := CalculateType(mul) // 将mul函数强制转换成CalculateType类型
	a.Serve(2, 3)
	b.Serve(2, 3)
}
// 5
// 我是一个函数类型
// 6
// 我是一个函数类型

再写一个例子我们来理解为什么要用type function

1.原始结构体实现接口

package main
import "fmt"
type Handler interface { //定义一个处理器接口,用来做处理
	Do(k, v string)
}
//定义一个Each函数,接受Handler处理器的一个实例和map,把map遍历出来给Do
//然后做什么就取决于h这个handler处理器了
func Each(m map[string]string, h Handler) {
	if m != nil && len(m) > 0 {
		for k, v := range m {
			h.Do(k, v)
		}
	}
}
type weclome string //定义一个weclome类型
//weclome类型实现了Handler处理器接口,他用来做自我介绍
func (w weclome) Do(k, v string) {
	// fmt.Println(w, ",我叫:", k, "今年", v, "岁")
	fmt.Printf("%s,我叫%s,今年%s岁\n", w, k, v)
}
func main() {
	people := make(map[string]string)
	people["张三"] = "18"
	people["李四"] = "19"
	people["小明"] = "20"
	var w weclome
	w = "大家好"
	Each(people, w)

}
# 大家好,我叫张三,今年18岁
# 大家好,我叫李四,今年19岁
# 大家好,我叫小明,今年20岁

以上实现,主要有两点不太好:

  • 因为必须要实现Handler接口,Do这个方法名不能修改,不能定义一个更有意义的名字
  • 必须要新定义一个类型,才可以实现Handler接口,才能使用Each函数

2.接口型函数出场

首先我们先解决第一个问题,根据我们具体做的事情定义一个更有意义的方法名,比如例子中是自我介绍,那么使用selfInfo要比Do这个干巴巴的方法要好的多。

package main
import "fmt"
type Handler interface { //定义一个处理器接口,用来做处理
	Do(k, v string)
}
type HandlerFunc func(k, v string)
func (h HandlerFunc) Do(k, v string) {
	h(k, v)
}
//定义一个Each函数,接受HandlerFunc处理器的一个实例和map,把map遍历出来给Do
//然后做什么就取决于h这个HandlerFunc处理器了
func Each(m map[string]string, h HandlerFunc) {
	if m != nil && len(m) > 0 {
		for k, v := range m {
			h.Do(k, v)
		}
	}
}
func selfinfo(k, v string) {
	fmt.Printf("大家好,我叫%s,今年%s岁\n", k, v)
}
func selfinfo1(k, v string) {
	fmt.Printf("大家好,接下来上台的是%s,今年%s岁\n", k, v)
}
func main() {
	people := make(map[string]string)
	people["张三"] = "18"
	people["李四"] = "19"
	people["小明"] = "20"
	Each(people, HandlerFunc(selfinfo))
	Each(people, HandlerFunc(selfinfo1))

}
# 大家好,我叫小明,今年20岁
# 大家好,我叫张三,今年18岁
# 大家好,我叫李四,今年19岁
# 大家好,接下来上台的是李四,今年19岁
# 大家好,接下来上台的是小明,今年20岁
# 大家好,接下来上台的是张三,今年18岁

不同的场景可以用不同的函数,但是每次强制转型不太好,我们继续重构,可以采用新定义一个函数的方式,帮助调用者强制转型。

func EachFunc(m map[string]string, f func(k, v string)) {
	Each(m, HandlerFunc(f))
}

现在我们发现EachFunc函数接收的是一个func(k, v string)类型的函数,没有必要实现Handler接口了

func main() {
	people := make(map[string]string)
	people["张三"] = "18"
	people["李四"] = "19"
	people["小明"] = "20"
	// Each(people, HandlerFunc(selfinfo))
	// Each(people, HandlerFunc(selfinfo1))
	EachFunc(people, selfinfo)
}
# 大家好,我叫小明,今年20岁
# 大家好,我叫张三,今年18岁
# 大家好,我叫李四,今年19岁

大体的type function的用法,可以理解一下,真的是脑子要想爆炸了

 收藏 (0) 打赏

您可以选择一种方式赞助本站

支付宝扫一扫赞助

微信钱包扫描赞助

未经允许不得转载:家里蹲的狐狸 » golang中 type func() 用法分析

分享到: 生成海报
avatar

评论 抢沙发

  • QQ号
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

登录

忘记密码 ?

切换登录

注册

我们将发送一封验证邮件至你的邮箱, 请正确填写以完成账号注册和激活