Go语言的匿名函数与闭包深入理解

栏目: Go · 发布时间: 5年前

内容简介:有空学习Go语言的匿名函数与闭包,做个记录,以待深入理解。当我们不希望给函数起名字的时候,可以使用匿名函数,例如:func(x, y int) int { return x + y }。这样的一个函数不能够独立存在(编译器会返回错误:non-declaration statement outside function body),但可以被赋值于某个变量,即保存函数的地址到变量中:fplus := func(x, y int) int { return x + y },然后通过变量名对函数进行调用:fplu

有空学习 Go 语言的匿名函数与闭包,做个记录,以待深入理解。

闭包

当我们不希望给函数起名字的时候,可以使用匿名函数,例如:func(x, y int) int { return x + y }。

这样的一个函数不能够独立存在(编译器会返回错误:non-declaration statement outside function body),但可以被赋值于某个变量,即保存函数的地址到变量中:fplus := func(x, y int) int { return x + y },然后通过变量名对函数进行调用:fplus(3,4)。

当然,您也可以直接对匿名函数进行调用:func(x, y int) int { return x + y } (3, 4)。

下面是一个计算从 1 到 1 百万整数的总和的匿名函数:

func() {

sum := 0

for i := 1; i <= 1e6; i++ {

sum += i

}

}()

表示参数列表的第一对括号必须紧挨着关键字 func,因为匿名函数没有名称。花括号 {} 涵盖着函数体,最后的一对括号表示对该匿名函数的调用。

下面的例子展示了如何将匿名函数赋值给变量并对其进行调用(function_literal.go):

package main

import "fmt"

func main() {

f()

}

func f() {

for i := 0; i < 4; i++ {

g := func(i int) { fmt.Printf("%d ", i) } //此例子中只是为了演示匿名函数可分配不同的内存地址,在现实开发中,不应该把该部分信息放置到循环中。

g(i)

fmt.Printf(" - g is of type %T and has value %v\n", g, g)

}

}

输出:

0  - g is of type func(int) and has value 0x486470

1  - g is of type func(int) and has value 0x486470

2  - g is of type func(int) and has value 0x486470

3  - g is of type func(int) and has value 0x486470

如下图:

Go语言的匿名函数与闭包深入理解

我们可以看到变量 g 代表的是 func(int),变量的值是一个内存地址。

所以我们实际上拥有的是一个函数值:匿名函数可以被赋值给变量并作为值使用。

在 main 函数中写一个用于打印 Hello World 字符串的匿名函数并赋值给变量 fv,然后调用该函数并打印变量 fv的类型。

匿名函数像所有函数一样可以接受或不接受参数。下面的例子展示了如何传递参数到匿名函数中:

func (u string) {

fmt.Println(u)

}(v)

请学习以下示例并思考(return_defer.go):函数 f 返回时,变量 ret 的值是什么?

package main

import "fmt"

func f() (ret int) {

defer func() {

ret++

}()

return 1

}

func main() {

fmt.Println(f())

}

如下图:

Go语言的匿名函数与闭包深入理解

变量 ret 的值为 2,因为 ret++ 是在执行 return 1 语句后发生的。

这可用于在返回语句之后修改返回的 error 时使用。

defer 语句和匿名函数

关键字 defer 经常配合匿名函数使用,它可以用于改变函数的命名返回值。

匿名函数还可以配合 go 关键字来作为 goroutine 使用。

匿名函数同样被称之为闭包(函数式语言的术语):它们被允许调用定义在其它环境下的变量。闭包可使得某个函数捕捉到一些外部状态,例如:函数被创建时的状态。另一种表示方式为:一个闭包继承了函数所声明时的作用域。这种状态(作用域内的变量)都被共享到闭包的环境中,因此这些变量可以在闭包中被操作,直到被销毁。闭包经常被用作包装函数:它们会预先定义好 1 个或多个参数以用于包装。另一个不错的应用就是使用闭包来完成更加简洁的错误检查。

Linux公社的RSS地址https://www.linuxidc.com/rssFeed.aspx

本文永久更新链接地址: https://www.linuxidc.com/Linux/2018-11/155321.htm


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

STL源码剖析

STL源码剖析

侯捷 / 华中科技大学出版社 / 2002-6 / 68.00元

学习编程的人都知道,阅读、剖析名家代码乃是提高水平的捷径。源码之前,了无秘密。大师们的缜密思维、经验结晶、技术思路、独到风格,都原原本本体现在源码之中。 这本书所呈现的源码,使读者看到vector的实现、list的实现、heap的实现、deque的实现、Red Black tree的实现、hash table的实现、set/map的实现;看到各种算法(排序、查找、排列组合、数据移动与复制技术......一起来看看 《STL源码剖析》 这本书的介绍吧!

html转js在线工具
html转js在线工具

html转js在线工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具