首页 文章资讯内容详情

golang中函数类型

2026-06-01 4 花语

本文内容纲要:

今天看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