有人在围棋中文网微信群里问了这样一个问题:(想进群的请在公众号回复消息“进群”)群友的提问,语法是什么?为什么没有参数?对于某些人来说,这根本不是问题,但对于其他人来说,这根本就没有意义。我提到函数在Go中是一等公民,但不清楚那是什么意思。似乎有必要解释一下什么是一等公民。在您进一步了解之前,您能说出什么是一等公民吗?对于一等公民[1](First-classcitizen)看维基百科的定义:在编程语言设计中,给定编程语言中的一等公民(也称类型、对象、实体或值)是一个实体,它支持其他实体通常可用的所有操作。这些操作通常包括作为参数传递、从函数返回、修改和分配给变量。大致的思路是,在编程语言中,所谓的一等公民是指支持所有操作的实体,通常包括作为参数传递、从函数返回、修改和赋值给变量等。例如,int类型支持作为参数传递,可以从函数返回,也可以赋值给变量,所以是一等公民。同样,函数是一等公民,这意味着它们可以赋值给变量或存储在数据结构中,可以作为其他函数的参数或返回值。关于函数作为一等公民,在维基百科[2]中也有定义。在计算机科学中,如果一种编程语言将函数视为一等公民,则称该语言具有一等函数。这意味着该语言支持将函数作为参数传递给其他函数,将它们作为其他函数的值返回,并支持变量或将它们存储在数据结构中。一些编程语言理论家也需要支持匿名函数(函数文字)。在具有一等函数的语言中,函数的名称没有任何特殊地位;具有功能类型。这个词是ChristopherStrachey在20世纪60年代中期在“作为一等公民的职能”的背景下创造的。带大。然而,并非所有语言都将函数视为一等公民,尤其是在早期。比如C语言中的函数不是一等公民,有些函数是通过函数指针实现的;添加。一般来说,在函数式编程语言、动态语言和现代编程语言中,函数都被视为一等公民,例如Scala和Julia等函数式语言,JavaScript和Python等动态语言,以及现代编译器例如Go、Rust和Swift。键入语言。为了让大家对函数作为一等公民有更深的理解,我们来看看Go语言是如何支持上文提到的一等公民函数的。匿名函数函数一般都有名字,但有时没有名字的函数更简洁易用。没有名字的函数称为匿名函数。下面是Go语言中的一个匿名函数的例子::%T\n",fn)}//output://Thisisanonymousfunction!//Thetypeoffn:func()在线运行:https://play.studygolang.com/p/IcInzZsAr0a。在Go中,匿名函数最常用的场景就是启动一个goroutine,经常会看到这样的代码:gofunc(){//xxxx}()匿名函数定义后立即被调用。另外,在defer语句中也很常见。定义函数类型定义函数类型和其他类型类似,后半部分和匿名函数类似,只是没有函数实现。比如net/http包中的HandlerFunc函数类型:typeHandlerFuncfunc(ResponseWriter,*Request)如何使用这个类型?如果你能看懂这段代码,就说明你看懂了:varhhttp.HandlerFunc=func(wResponseWriter,req*Request){fmt.fprintln(w,"HelloWorld!")}函数作为参数是指一个函数作为另一个函数的参数,即回调,这在JS中很常见。在Go语言中也经常出现。文章开头的问题是关于函数作为参数的。根据Gin的API定义,router.GET方法的签名如下:func(group*RouterGroup)GET(relativePathstring,handlers...HandlerFunc)IRoutes其中HandlerFunc是一个函数类型,其定义如下:typeHandlerFuncfunc(*Context)所以,在router.GET("/users",Users)中,Users只是GET函数的一个参数,参数类型为HandlerFunc,Users的定义只需要符合HandlerFunc即可:funcUsers(ctx*gin.Context){}因为这里函数Users作为参数,所以自然不需要给Users传递参数,Uers的调用内部负责GET,也就是所谓的打回来。Functionsasreturnvalues函数作为返回值,在Go中,这样的函数必须是匿名函数。在做web开发的时候,中间件会使用上面的函数作为返回值。以Gin为例,定义一个Logger中间件:funcLogger()gin.HandlerFunc{returnfunc(c*gin.Context){t:=time.Now()//Setexamplevariablec.Set("example","12345")//beforerequestc.Next()//afterrequestlatency:=time.Since(t)log.Print(latency)//accessthestatuswearesendingstatus:=c.Writer.Status()log.Println(status)}}由上可知,gin.HandlerFunc是一个函数类型,所以我们需要返回一个该类型的实例,匿名函数(函数字面值)只需要与gin.HandlerFunc类型的底层类型一致,会进行隐式转换,所以可以直接返回匿名类型func(c*gin.Context){}。经常听到高阶函数,函数是一等公民,支持高阶函数。只要一个函数接收一个或多个函数类型参数;或返回一个函数,这样的函数称为高阶函数。闭包闭包是匿名函数的特例。当匿名函数访问的变量定义在函数体之外时,这样的匿名函数称为闭包。一个简单的例子:packagemainimport("fmt")funcmain(){a:=5func(){fmt.Println("a=",a)}()}在上面的程序中,匿名函数在第10行变量上被访问a,a存在于函数体之外。所以这个匿名函数就是闭包。总结以上知识点,可以说是学习现代编程语言的必备之物。如果还有不明白的地方欢迎留言交流。最后需要注意的是,Go不支持命名函数的嵌入。也就是说,Go不支持类似JavaScript的语法:functionouter(){console.log("Inouterfunction");functioninner(){console.log("Ininnerfunction");}}Go只能通过匿名函数来实现。参考资料[1]一等公民:https://en.wikipedia.org/wiki/First-class_citizen[2]维基百科也有定义:https://en.wikipedia.org/wiki/First-class_function[3]ChristopherStrachey:https://en.wikipedia.org/wiki/Christopher_Strachey本文转载自微信公众号「polarisxu」,可通过以下二维码关注。转载本文请联系polarisxu公众号。
