golang中函数类型
本文内容纲要:
今天看Martini文档,其功能列表提到完全兼容http.HandlerFunc
接口,就去查阅了Go:net/http的文档,看到typeHandlerFunc这部分,顿时蒙圈了。由于之前学习的时候没有关注过functiontypes的知识点,就Google了一些文章,才算是有了个大概的了解。
从golang的官方文档得知functiontypes的解释是这样的。
Afunctiontypedenotesthesetofallfunctionswiththesameparameterandresulttypes.
先找个例子来看一下:
packagemain
import"fmt"
//Greetingfunctiontypes
typeGreetingfunc(namestring)string
funcsay(gGreeting,nstring){
fmt.Println(g(n))
}
funcenglish(namestring)string{
return"Hello,"+name
}
funcmain(){
say(english,"World")
}
输出Hello,World
say()函数要求传入一个Greeting类型,因为english函数的参数和返回值跟Greeting一样,参考接口的概念这里可以做类型转换。我们换个方式来实现上面的功能:
packagemain
import"fmt"
//Greetingfunctiontypes
typeGreetingfunc(namestring)string
func(gGreeting)say(nstring){
fmt.Println(g(n))
}
funcenglish(namestring)string{
return"Hello,"+name
}
funcmain(){
g:=Greeting(english)
g.say("World")
}
同样输出Hello,World
,只是给Greeting类型添加了say()
方法。上面说了,函数类型是表示所有包含相同参数和返回类型的函数集合。我们在一开始先把func(namestring)string
这样的函数声明成Greeting
类型,接着我们通过Greeting(english)
将english
函数转换成Greeting
类型。通过这个转换以后,我们就可以借由变量g调用Greeting
类型的say()
方法。两段代码的差异就是go的类型系统添加方法和类C++语言添加类型方法的差异,具体讲解可以去查看《Go语言编程》第3章为类型添加方法这一节。
既然是函数集合,那么只有一个函数显然是不足以说明问题的。
packagemain
import"fmt"
//Greetingfunctiontypes
typeGreetingfunc(namestring)string
func(gGreeting)say(nstring){
fmt.Println(g(n))
}
funcenglish(namestring)string{
return"Hello,"+name
}
funcfrench(namestring)string{
return"Bonjour,"+name
}
funcmain(){
g:=Greeting(english)
g.say("World")
g=Greeting(french)
g.say("World")
}
输出
Hello,World
Bonjour,World
在其他语言里面,有些函数可以直接作为参数传递,有些是以函数指针进行传递,但是都没有办法像go这样可以给函数类型“增加”新方法。
回到Go:net/http的HandlerFunc类型,只要Martini的函数遵循文档中typeHandlerFuncfunc(ResponseWriter,*Request)
的要求,就可以转换成HandlerFunc类型,也就可以调用func(HandlerFunc)ServeHTTP
函数。
在Go语言中,我们可以把函数作为一种变量,用type去定义它,那么这个函数类型就可以作为值传递,甚至可以实现方法,这一特性是在太灵活了,有时候我们甚至可以利用这一特性进行类型转换。作为值传递的条件是类型具有相同的参数以及相同的返回值。
函数的类型转换
Go语言的类型转换基本格式如下:
type_name(expression)
复制代码
举个例子:
packagemain
import"fmt"
typeCalculateTypefunc(int,int)//声明了一个函数类型
//该函数类型实现了一个方法
func(c*CalculateType)Serve(){
fmt.Println("我是一个函数类型")
}
//加法函数
funcadd(a,bint){
fmt.Println(a+b)
}
//乘法函数
funcmul(a,bint){
fmt.Println(a*b)
}
funcmain(){
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()方法。
函数作参数传递
packagemain
import"fmt"
typeCalculateTypefunc(a,bint)int//声明了一个函数类型
//加法函数
funcadd(a,bint)int{
returna+b
}
//乘法函数
funcmul(a,bint)int{
returna*b
}
funcCalculate(a,bint,fCalculateType)int{
returnf(a,b)
}
funcmain(){
a,b:=2,3
fmt.Println(Calculate(a,b,add))
fmt.Println(Calculate(a,b,mul))
}
//5
//6
复制代码
如上例子,Calculate的f参数类型为CalculateType,add和mul函数具有和CalculateType函数类型相同的参数和返回值,因此可以将add和mul函数作为参数传入Calculate函数中。
net/http包源码例子
//HandleFuncregistersthehandlerfunctionforthegivenpattern
//intheDefaultServeMux.
//ThedocumentationforServeMuxexplainshowpatternsarematched.
funcHandleFunc(patternstring,handlerfunc(ResponseWriter,*Request)){
DefaultServeMux.HandleFunc(pattern,handler)
}
复制代码
//HandleFuncregistersthehandlerfunctionforthegivenpattern.
func(mux*ServeMux)HandleFunc(patternstring,handlerfunc(ResponseWriter,*Request)){
mux.Handle(pattern,HandlerFunc(handler))
}
复制代码
typeHandlerFuncfunc(ResponseWriter,*Request)
//ServeHTTPcallsf(w,r).
func(fHandlerFunc)ServeHTTP(wResponseWriter,r*Request){
f(w,r)
}
复制代码
刚开始看到这段源码的时候,真的有点懵逼了,这段源码的目的是为了将我们的Handler强制实现ServeHTTP()方法,如下例子:
funcsayHi(whttp.ResponseWriter,r*http.Request){
io.WriteString(w,"hi")
}
funcmain(){
http.HandlerFunc("/",sayHi)
http.ListenAndserve(":8080",nil)
}
复制代码
因为HandlerFunc是一个函数类型,而sayHi函数拥有和HandlerFunc函数类型一样的参数值,因此可以将sayHi强制转换成HandlerFunc,因此sayHi也拥有了ServeHTTP()方法,也就实现了Handler接口,同时,HandlerFunc的ServeHTTP方法执行了它自己本身,也就是sayHi函数,这也就可以看出来了,sayHi就是Handler被调用之后的执行结果。
//TheHandlerFunctypeisanadaptertoallowtheuseof
//ordinaryfunctionsasHTTPhandlers.Iffisafunction
//withtheappropriatesignature,HandlerFunc(f)isa
//Handlerthatcallsf.
typeHandlerFuncfunc(ResponseWriter,*Request)
//ServeHTTPcallsf(w,r).
func(fHandlerFunc)ServeHTTP(wResponseWriter,r*Request){
f(w,r)
}
//HandleFuncregistersthehandlerfunctionforthegivenpattern.
func(mux*ServeMux)HandleFunc(patternstring,handlerfunc(ResponseWriter,*Request)){
ifhandler==nil{
panic("http:nilhandler")
}
mux.Handle(pattern,HandlerFunc(handler))
}
//Handleregistersthehandlerforthegivenpattern
//intheDefaultServeMux.
//ThedocumentationforServeMuxexplainshowpatternsarematched.
funcHandle(patternstring,handlerHandler){DefaultServeMux.Handle(pattern,handler)}
//HandleFuncregistersthehandlerfunctionforthegivenpattern
//intheDefaultServeMux.
//ThedocumentationforServeMuxexplainshowpatternsarematched.
funcHandleFunc(patternstring,handlerfunc(ResponseWriter,*Request)){
DefaultServeMux.HandleFunc(pattern,handler)
}
//ServeacceptsincomingHTTPconnectionsonthelistenerl,
//creatinganewservicegoroutineforeach.Theservicegoroutines
//readrequestsandthencallhandlertoreplytothem.
//
//Thehandleristypicallynil,inwhichcasetheDefaultServeMuxisused.
//
//HTTP/2supportisonlyenablediftheListenerreturns*tls.Conn
//connectionsandtheywereconfiguredwith"h2"intheTLS
//Config.NextProtos.
//
//Servealwaysreturnsanon-nilerror.
funcServe(lnet.Listener,handlerHandler)error{
srv:=&Server{Handler:handler}
returnsrv.Serve(l)
}
本文内容总结:
原文链接:https://www.cnblogs.com/igoodful/p/11519695.html