Go 语言基础入门教程 —— 函数篇:匿名函数和闭包

Wesley13
• 阅读 589

匿名函数

熟悉 Laravel 框架(一个 PHP Web 框架)的同学对匿名函数应该很熟悉,Laravel 框架中有着大量匿名函数的应用场景,比如路由定义、绑定实现到接口等:

// 路由定义

再比如 Swoole 中通过回调函数处理网络事件实现异步事件驱动也是匿名函数的典型应用场景:

//收到请求时触发

可以看到,匿名函数是一种不需要定义函数名的函数声明方式,在多种编程语言中都有实现和支持,比如 PHP、JavaScript(想想 ajax 的实现)等,Go 语言中也提供了对匿名函数的支持,并且形式上和 PHP 类似,无非是要声明参数类型和返回值类型而已:

func(a, b int) int { 

和 PHP 一样,Go 语言的匿名函数可以赋值给一个变量或者直接执行:

add := func(a, b int) int {

闭包

Go 语言的匿名函数是一个闭包(Closure),下面我们先来了解一下闭包的概念、价值和应用场景。

闭包的概念和价值

所谓闭包指的是引用了自由变量(未绑定到特定对象的变量,通常在匿名函数外定义)的函数,被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的上下文环境也不会被释放(比如传递到其他函数或对象中)。或者通俗点说,「闭」的意思是「封闭外部状态」,即使外部状态已经失效,闭包内部依然保留了一份从外部引用的变量。

闭包的价值在于可以作为函数对象或者匿名函数,对于类型系统而言,这意味着不仅要表示数据还要表示代码。支持闭包的多数语言都将函数作为第一类对象(firt-class object,有的地方也译作第一级对象,第一类公民等),就是说这些函数可以存储到变量中作为参数传递给其他函数,能够被函数动态创建和返回。

注:所谓第一类对象指的是运行期可以被创建并作为参数传递给其他函数或赋值给变量的实体,在绝大多数语言中,数值和基本类型都是第一类对象,在支持闭包的编程语言中(比如 Go、PHP、JavaScript、Python 等),函数也是第一类对象,而像 C、C++ 等不支持闭包的语言中,函数不能在运行期创建,所以在这些语言中,函数不是不是第一类对象。

Go 语言中闭包的应用场景

Go 语言中的闭包同样也会引用函数外定义的变量,只要闭包还在被使用,那么被闭包引用的变量会一直存在。

下面我们来看一下 Go 语言中闭包的几个应用示例。

保证局部变量的安全性

闭包内部声明的局部变量无法从外部修改,从而确保了安全性(类似类的私有属性):

var j int = 1

上述代码输出结果如下:

i, j: 1, 1i, j: 1, 3

在上面的示例中,变量 f 指向的闭包引用了局部变量 i 和 ji 在闭包内部定义,其值被隔离,不能从外部修改,而变量 j 在闭包外部定义,所以可以从外部修改,闭包持有的只是其引用。

将匿名函数作为参数

我们可以先声明一个外部函数的参数为函数类型,然后定义一个闭包并赋值给指定变量,再将这个变量传递到外部函数中:

import "fmt"

上述代码的打印结果是:

Variable i from main func: 10The sum of 1 and 2 is: 3

通过这个示例,我们还验证了虽然 i 变量声明在 main 函数中,在调用 callback 外部函数时传入了匿名函数 add作为参数,add 函数在外部函数中执行,虽然作用域离开了 main 函数,但是还是可以访问到变量 i

将匿名函数作为返回值

最后,我们来演示下闭包作为函数返回值的示例:

package main

上述代码的打印结果是 3。我们声明 addfunc 函数的返回值是一个函数,并且在 return 时返回一个闭包,这个闭包可以访问外部函数的参数和变量,并持有这些变量,只要闭包存在,这些变量就一直存在,即使脱离了 addfunc 函数的作用域,依然可以访问它们。

本文分享自微信公众号 - xueyuanjun(geekacademy)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
JS 对象数组Array 根据对象object key的值排序sort,很风骚哦
有个js对象数组varary\{id:1,name:"b"},{id:2,name:"b"}\需求是根据name或者id的值来排序,这里有个风骚的函数函数定义:function keysrt(key,desc) {  return function(a,b){    return desc ? ~~(ak
Stella981 Stella981
2年前
HIVE 时间操作函数
日期函数UNIX时间戳转日期函数: from\_unixtime语法:   from\_unixtime(bigint unixtime\, string format\)返回值: string说明: 转化UNIX时间戳(从19700101 00:00:00 UTC到指定时间的秒数)到当前时区的时间格式举例:hive   selec
Wesley13 Wesley13
2年前
go 的匿名函数和闭包
匿名函数匿名函数是指不需要定义函数名的一种函数实现方式。在Go语言中,函数可以像普通变量一样被传递或使用,这与C语言的回调函数比较类似。不同的是,Go语言支持随时在代码里定义匿名函数。匿名函数由一个不带函数名的函数声明和函数体组成,如下所示:!(https://
Easter79 Easter79
2年前
Swift3.0 闭包(blcok)的全面介绍及使用
闭包是自包含的函数代码块,可以在代码中被传递和使用。Swift中的闭包与C和ObjectiveC中的代码块(blocks)以及其他一些编程语言中的匿名函数比较相似。闭包可以捕获和存储其所在上下文中任意常量和变量的引用。被称为包裹常量和变量。Swift会为你管理在捕获过程中涉及到的所有内存操作。闭包表达式语法有如下的一般形式:
Stella981 Stella981
2年前
Golang之匿名函数和闭包
Go语言支持匿名函数,即函数可以像普通变量一样被传递或使用。使用方法如下:main.go!复制代码(https://oscimg.oschina.net/oscnet/cf4405f1d31ed55912b22f881ff1e165bba.gif)packagemainimport("fm
Wesley13 Wesley13
2年前
PHP匿名函数及闭包
匿名函数在编程语言中出现的比较早,最早出现在Lisp语言中,随后很多的编程语言都开始有这个功能了,目前使用比较广泛的Javascript以及C,PHP直到5.3才开始真正支持匿名函数,C的新标准C0x也开始支持了。匿名函数是一类不需要指定标示符,而又可以被调用的函数或子例程,匿名函数可以方便的作为参数传递给其他函数,最常见应用是作为回调函数
Wesley13 Wesley13
2年前
PHP匿名函数及闭包(精讲)
匿名函数在编程语言中出现的比较早,最早出现在Lisp语言中,随后很多的编程语言都开始有这个功能了,目前使用比较广泛的JavaScript以及C,PHP直到5.3才开始真正支持匿名函数,C的新标准C0x也开始支持了。匿名函数是一类不需要指定标示符,而又可以被调用的函数或子例程,匿名函数可以方便的作为参数传递给其他函数,最常见应
Stella981 Stella981
2年前
Javascript技巧
匿名立即执行函数1//匿名立即执行函数