Go语言中type func()的的使用分析

在Go语言中可以通过type来定义变量类型,在学习源码的过程中经常会看到一种type func()的定义方式,刚开始的时候有点难以理解,现在对这种方法做一下分析。

1.案例分析

在使用**“github.com/robfig/cron”**库创建定时任务时就会用到type func()这种定义类型的方式:

func CreateCron() {
	//创建定时任务
	i := 0
	c := cron.New()
	spec := "*/5 * * * * ?"
	// AddFunc的第二个参数就是函数类型
	if err := c.AddFunc(spec, func() {
		i++
		log.Println("cron running:", i)
	}); err != nil {
		log.Println(err)
	}
	c.Start()
}

查看AddFunc()源码,可以发现,AddFunc方法的第二个参数时func()类型:

// AddFunc adds a func to the Cron to be run on the given schedule.
func (c *Cron) AddFunc(spec string, cmd func()) error {
	return c.AddJob(spec, FuncJob(cmd))
}

这个方法调用了AddJob(spec, FuncJob(cmd)),AddJob方法的第二个参数是Job类型,因此在调用AddJob方法时通过 FuncJob(cmd)将cmd转换为FuncJob类型,而Job是一个接口,FuncJob实现了Job接口的Run方法,而Run方法就做了一件事就是执行FunJob这个函数。

// A wrapper that turns a func() into a cron.Job
type FuncJob func()

func (f FuncJob) Run() { f() }

// Job is an interface for submitted cron jobs.
type Job interface {
	Run()
}

分析到这里,大家应该明白了type func()类型的使用方法,但是这里的func()类型是没有参数的,如果函数类型中有参数,那这个参数是如何传递的?下面再说一个案例:

func Http() {
	http.HandleFunc("/", h)
}
func h(w http.ResponseWriter, r *http.Request) {
	return
}

上面的HandleFunc方法的第二个参数是一个带参数的函数类型

// DefaultServeMux is the default ServeMux used by Serve.
var DefaultServeMux = &defaultServeMux

// 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将传进来的函数强制转换为HandlerFunc类型,HandlerFunc类型实现了Handler接口的ServerHTTP方法,这样就可以调用Handle方法了。

// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as HTTP handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler that calls f.
type HandlerFunc func(ResponseWriter, *Request)

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

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

注意:这个案例中传入的函数是有参数的,在这里参数的作用相当于声明参数,在使用函数类型的变量时,并不能传入参数。

2. 应用

说了这么多,我们来应用一下type func()的使用方法。

// 定义ISay接口,这个接口实现了Say方法
type ISay interface {
	Say()
}

// 定义函数类型的SayFunc
type SayFunc func()

// 实现ISay接口的Say方法,注意这里不能使用*SayFunc,否则会报错
func (s SayFunc) Say() {
	s()
}

// 入口函数具体执行的函数
func say(iSay ISay) {
	iSay.Say()
}

// 入口函数
func Say(handler func()){
	say(SayFunc(handler))
}

// 定义一个函数
func SayHello() {
	fmt.Println("Hello World")
}
func main() {
	Say(SayHello)
}

这个例子使用函数类型的变量,最终输出了一个Hello World,看起来好像没有必要,直接调用SayHello函数不是更简单吗,是的,这样更简单,但是如果你要写一个库,他必须要让使用者可以自定义方法执行的步骤,比如案例一中,定时任务具体执行的操作要由使用者定义,那么就必须要用到函数类型的参数,这样用户就可以很方便的自定义定时任务的具体操作,案例二也是同样的。

猜你喜欢

转载自blog.csdn.net/random_w/article/details/106284116
今日推荐