请问下各位大佬,这是什么语法,为什么不需要参数的?

对于有些人来说这根本不是问题,但有些人却想不明白。我提到,在 Go 语言中,函数是一等公民,但对方不清楚这到底在说什么。看来有必要解释下什么是一等公民。

再往下看之前,你能说出什么是一等公民吗?

关于一等公民[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 mainimport ("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 variablec.Set("example", "12345")// before requestc.Next()// after requestlatency := time.Since(t)log.Print(latency)// access the status we are sendingstatus := c.Writer.Status()log.Println(status)}
}

从上文知道,gin.HandlerFunc 是一个函数类型,因此需要返回一个该类型的实例,而匿名函数(函数字面值)只要和 gin.HandlerFunc 类型的底层类型一致,会进行隐式转换,所以可以直接返回 func(c *gin.Context) {} 这个匿名类型。

经常听到高阶函数,函数是一等公民,就支持高阶函数。一个函数只要接收一个或多个函数类型参数;亦或是返回一个函数,这样的函数就叫做高阶函数。

闭包

闭包(Closure)是匿名函数的一个特例。当一个匿名函数所访问的变量定义在函数体的外部时,就称这样的匿名函数为闭包

一个简单的例子:

package mainimport (  "fmt"
)func main() {  a := 5func() {fmt.Println("a =", a)}()
}

总结

以上的知识点,可以说是学习现代编程语言必须会的。如果你还有哪个点不明白,欢迎留言交流。

最后说明一点,Go 是不支持命名函数内嵌的。即类似 JavaScript 中这样的语法,Go 不支持:

function outer() {console.log("In outer function");function inner() {console.log("In inner function");}
}

Go 只能通过匿名函数来实现。

函数是一等公民,这到底在说什么?相关推荐

  1. JavaScript学习笔记——函数 Part4:向函数传递函数、从函数返回函数(函数是一等公民)

    要点 函数是值,这个值就是函数引用 函数是一等公民:函数引用是一等值 可将函数引用赋给变量.含在数据结构(如对象)中.传递给其他函数或从其他函数返回 函数是一等公民 不要再认为函数是特殊的,有别于Ja ...

  2. 如何理解python中的函数_如何理解“python中函数是一等公民”?

    python.js.scala等支持函数式编程的语言中,是如何体现"函数是一等公民(first class)"的?而在c/c++.java等静态语言中的一等公民又是什么?如何体现的 ...

  3. 函数式编程 -- 函数是一等公民、高阶函数、闭包

    文章内容输出来源:拉勾教育 大前端高薪训练营 前言 学习函数式编程,首先要了解函数式编程相关的概念. 一.函数是一等公民 1. 一等公民的定义 根据维基百科,编程语言中一等公民的概念是由英国计算机学家 ...

  4. JavaScript深入浅出第2课:函数是一等公民是什么意思呢?

    摘要: 听起来很炫酷的一等公民是啥? <JavaScript深入浅出>系列: JavaScript深入浅出第1课:箭头函数中的this究竟是什么鬼? JavaScript深入浅出第2课:函 ...

  5. python定义公民类_Python-理解函数为”一等公民”

    Python中一切皆对象,函数也是对象,也就是说对象能干什么.函数也能干.如拥有原生属性.自定义创建.动态赋值.作为参数传递.作为返回值返回. 作为"一等公民"的函数 一等公民?对 ...

  6. 【Golang】函数(一等公民)的使用

    文章目录 函数的声明(定义) 普通函数声明 函数的返回值 调用函数 Go语言变量 匿名函数 定义一个匿名函数 使用函数类型实现接口 Go语言闭包(Closure)--引用了外部变量的匿名函数 在闭包内 ...

  7. Go 学习笔记(61)— Go 高阶函数、函数作为一等公民(函数作为输入参数、返回值、变量)的写法

    函数在 Go 语言中属于"一等公民(First-Class Citizen)"拥有"一等公民"待遇的语法元素可以如下使用 可以存储在变量中: 可以作为参数传递给 ...

  8. js系列十七:函数是一等公民

    所谓的一等公民,其实就是普通函数,也就是说,函数其实就是没有什么特殊的,我们可以像对待其他数据类型一样对待函数. 1 可以把函数赋值给一个变量 var fn = function () {}; 2 ` ...

  9. 函数式编程范式:函数是一等公民

    目录 如果有小伙伴想要回顾之前的知识的话,点击下面的链接查看之前所有的学习栏目

最新文章

  1. OpenCV 【四】————Watershed Algorithm(图像分割)——分水岭算法的原理及实现
  2. 【关注】3000多警力围剿“毒村”!现实比影视剧更惊险
  3. Android系统架构图及简单的系统架构介绍
  4. 内核对象用于线程同步
  5. java文件名特殊字符_Java 8:用名字读取特殊字符的文件
  6. sqlite的几个常用方法
  7. Linux下locale: Cannot set LC_CTYPE to default locale: No such file or directory警告
  8. mysql 索引 原理_MySQL索引实现原理分析
  9. arcgis插值不覆盖区划图_ArcGIS绘图—空气质量站点数据插值绘制等值线图
  10. .Net框架集WebClient类向WinCE平台上传文件(FTP方式)延迟15秒释疑
  11. java里的foreach迭代器_java 中 for 、foreach 和 迭代器 的学习笔记
  12. Moodle 安装的时候提示 original IP
  13. java tracert_tracert-命令小结
  14. 光伏发电沦为白菜价 看光伏大佬们如何“割肉”
  15. 提交订单微信付款逻辑
  16. 运行systeminfo时出现闪退现象
  17. 终于有人把红蓝对抗讲明白了
  18. [ERP]ERP项目实施过程中的致命过失
  19. 菜鸟窝出品】数据清洗、python与sklearn数据标准化实战(附项目源码)
  20. Python opencv:人眼/人脸识别并实时打码处理

热门文章

  1. 共享3d打印机ppt分享
  2. Kafka启动失败异常-InconsistentClusterIdException
  3. [16]质量控制工具 因果图-帕累托图-直方图-趋势图等
  4. docker环境安装jira(Linux系统)
  5. 01.精益敏捷项目管理——敏捷开发者指南笔记
  6. android+酷炫动画效果,Android简单酷炫点击动画(附源码)
  7. 优化Kubernetes横向扩缩HPA
  8. 386高校毕业设计选题
  9. 搜搜/soso、有道、搜狗/sogou、雅虎/Yahoo、url 参数分析
  10. 【Lintcode】1718. Minimize Malware Spread