为什么函数是一等公民
这篇文章主要讲解了“为什么函数是一等公民”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“为什么函数是一等公民”吧!
为企业提供成都网站制作、网站设计、外贸网站建设、网站优化、全网整合营销推广、竞价托管、品牌运营等营销获客服务。创新互联拥有网络营销运营团队,以丰富的互联网营销经验助力企业精准获客,真正落地解决中小企业营销获客难题,做到“让获客更简单”。自创立至今,成功用技术实力解决了企业“网站建设、网络品牌塑造、网络营销”三大难题,同时降低了营销成本,提高了有效客户转化率,获得了众多企业客户的高度认可!
关于一等公民[1](First-class citizen)看看维基百科的定义:
In programming language design, a first-class citizen (also type, object, entity, or value) in a given programming language is an entity which supports all the operations generally available to other entities. These operations typically include being passed as an argument, returned from a function, modified, and assigned to a variable.
大意是说,在编程语言中,所谓一等公民,是指支持所有操作的实体, 这些操作通常包括作为参数传递,从函数返回,修改并分配给变量等。
比如 int 类型,它支持作为参数传递,可以从函数返回,也可以赋值给变量,因此它是一等公民。
类似的,函数是一等公民,意味着可以把函数赋值给变量或存储在数据结构中,也可以把函数作为其它函数的参数或者返回值。关于函数是一等公民,在维基百科也有定义[2]。
In computer science, a programming language is said to have first-class functions if it treats functions as first-class citizens. This means the language supports passing functions as arguments to other functions, returning them as the values from other functions, and assigning them to variables or storing them in data structures. Some programming language theorists require support for anonymous functions (function literals) as well.In languages with first-class functions, the names of functions do not have any special status; they are treated like ordinary variables with a function type. The term was coined by Christopher Strachey in the context of "functions as first-class citizens" in the mid-1960s.
函数作为一等公民的概念是 1960 年由英国计算机学家 Christopher Strachey[3] 提出来的。然而,并非所有语言都将函数作为一等公民,特别是早期,比如 C 语言中函数就不是一等公民,一些功能通过函数指针来实现的;再比如 C++、Java 等,都是后来的版本才加上的。
一般来说,函数式编程语言、动态语言和现代的编程语言,函数都会作为一等公民,比如:Scala、Julia 等函数式语言,JavaScript、Python 等动态语言,Go、Rust、Swift 等现代的编译型语言。
为了让大家对函数是一等公民有更深的理解,针对上文提到的一等公民的一等功能,我们看看 Go 语言是如何支持的。
匿名函数
函数一般是有名字的,但有时候没有名字的函数更简洁、好用。没有名字的函数叫匿名函数。
以下是 Go 语言匿名函数的一个例子:
package main import ( "fmt" ) func main() { fn := func() { fmt.Println("This is anonymous function!") } fn() fmt.Printf("The type of fn: %T\n", fn) } // output: // This is anonymous function! // The type of fn: func()
在线运行:https://play.studygolang.com/p/IcInzZsAr0a。
在 Go 中,匿名函数最常使用的场景是开启一个 goroutine,经常会见到类似这样的代码:
go func() { // xxxx }()
这里匿名函数定义后立即调用。此外,defer 语句中也常见。
定义函数类型
定义函数类型和其他类型类似,同时后半部分和匿名函数类似,只不过没有函数实现。比如 net/http 包中的 HandlerFunc 函数类型:
type HandlerFunc func(ResponseWriter, *Request)
怎么使用这个类型?能看懂这样的代码,表示你理解了:
var h http.HandlerFunc = func(w ResponseWriter, req *Request) { fmt.Fprintln(w, "Hello World!") }
函数作为参数
意思是说,一个函数作为另一个函数的参数,也就是回调,在 JS 中很常见。在 Go 语言中也经常出现。文章开头的问题就是函数作为参数。根据 Gin 的 API 定义,router.GET 方法的签名如下:
func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes
其中 HandlerFunc 是一个函数类型,它的定义如下:
type HandlerFunc func(*Context)
所以,router.GET("/users", Users) 中,Users 只是 GET 函数的参数,参数类型是 HandlerFunc,而 Users 的定义只要符合 HandlerFunc 即可:
func Users(ctx *gin.Context) {}
因为这里将函数 Users 作为参数,所以自然不需要给 Users 传递参数,Uers 的调用有 GET 内部负责,即所谓的回调。
函数作为返回值
函数作为返回值,在 Go 中,这样的函数一定是匿名函数。在进行 Web 开发时,中间件就会使用上函数作为返回值,还是以 Gin 为例,定义一个 Logger 中间件:
func Logger() gin.HandlerFunc { return func(c *gin.Context) { t := time.Now() // Set example variable c.Set("example", "12345") // before request c.Next() // after request latency := time.Since(t) log.Print(latency) // access the status we are sending status := c.Writer.Status() log.Println(status) } }
从上文知道,gin.HandlerFunc 是一个函数类型,因此需要返回一个该类型的实例,而匿名函数(函数字面值)只要和 gin.HandlerFunc 类型的底层类型一致,会进行隐式转换,所以可以直接返回 func(c *gin.Context) {} 这个匿名类型。
经常听到高阶函数,函数是一等公民,就支持高阶函数。一个函数只要接收一个或多个函数类型参数;亦或是返回一个函数,这样的函数就叫做高阶函数。
闭包
闭包(Closure)是匿名函数的一个特例。当一个匿名函数所访问的变量定义在函数体的外部时,就称这样的匿名函数为闭包。
一个简单的例子:
package main import ( "fmt" ) func main() { a := 5 func() { fmt.Println("a =", a) }() }
在上面的程序中,匿名函数在第 10 行访问了变量 a,而 a 存在于函数体的外部。因此这个匿名函数就是闭包。
感谢各位的阅读,以上就是“为什么函数是一等公民”的内容了,经过本文的学习后,相信大家对为什么函数是一等公民这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是创新互联,小编将为大家推送更多相关知识点的文章,欢迎关注!
网页名称:为什么函数是一等公民
本文URL:http://ybzwz.com/article/jepjjg.html