1 带你了解go语言中的闭包-德赢Vwin官网 网
0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

带你了解go语言中的闭包

Linux爱好者 来源:gitbooks 作者:gitbooks 2021-11-02 15:27 次阅读

导读】什么是闭包?什么场景下会用闭包本文对 go 语言中的闭包做了详细介绍。

闭包是由函数及其相关引用环境组合而成的实体(即:闭包=函数+引用环境)。

Go中的闭包

闭包是函数式语言中的概念,没有研究过函数式语言的用户可能很难理解闭包的强大,相关的概念超出了本书的范围。Go语言是支持闭包的,这里只是简单地讲一下在Go语言中闭包是如何实现的。

funcf(iint)func()int{
returnfunc()int{
i++
returni
}
}

函数f返回了一个函数,返回的这个函数,返回的这个函数就是一个闭包。这个函数中本身是没有定义变量i的,而是引用了它所在的环境(函数f)中的变量i。

c1:=f(0)
c2:=f(0)
c1()//referencetoi,i=0,return1
c2()//referencetoanotheri,i=0,return1

c1跟c2引用的是不同的环境,在调用i++时修改的不是同一个i,因此两次的输出都是1。函数f每进入一次,就形成了一个新的环境,对应的闭包中,函数都是同一个函数,环境却是引用不同的环境。

变量i是函数f中的局部变量,假设这个变量是在函数f的栈中分配的,是不可以的。因为函数f返回以后,对应的栈就失效了,f返回的那个函数中变量i就引用一个失效的位置了。所以闭包的环境中引用的变量不能够在栈上分配。

escape analyze

在继续研究闭包的实现之前,先看一看Go的一个语言特性:

funcf()*Cursor{
varcCursor
c.X=500
noinline()
return&c
}

Cursor是一个结构体,这种写法在C语言中是不允许的,因为变量c是在栈上分配的,当函数f返回后c的空间就失效了。但是,在Go语言规范中有说明,这种写法在Go语言中合法的。语言会自动地识别出这种情况并在堆上分配c的内存,而不是函数f的栈上。

为了验证这一点,可以观察函数f生成的汇编代码:

MOVQ$type."".Cursor+0(SB),(SP)//取变量c的类型,也就是Cursor
PCDATA$0,$16
PCDATA$1,$0
CALL,runtime.new(SB)//调用new函数,相当于new(Cursor)
PCDATA$0,$-1
MOVQ8(SP),AX//取c.X的地址放到AX寄存器
MOVQ$500,(AX)//将AX存放的内存地址的值赋为500
MOVQAX,"".~r0+24(FP)
ADDQ$16,SP

识别出变量需要在堆上分配,是由编译器的一种叫escape analyze的技术实现的。如果输入命令:

gobuild--gcflags=-mmain.go

可以看到输出:

./main.gomovedtoheap:c
./main.go&cescapestoheap

表示c逃逸了,被移到堆中。escape analyze可以分析出变量的作用范围,这是对垃圾回收很重要的一项技术。

闭包结构体

回到闭包的实现来,前面说过,闭包是函数和它所引用的环境。那么是不是可以表示为一个结构体呢:

typeClosurestruct{
Ffunc()()
i*int
}

事实上,Go在底层确实就是这样表示一个闭包的。让我们看一下汇编代码:

funcf(iint)func()int{
returnfunc()int{
i++
returni
}
}


MOVQ$type.int+0(SB),(SP)
PCDATA$0,$16
PCDATA$1,$0
CALL,runtime.new(SB)//是不是很熟悉,这一段就是i=new(int)
...
MOVQ$type.struct{Fuintptr;A0*int}+0(SB),(SP)//这个结构体就是闭包的类型
...
CALL,runtime.new(SB)//接下来相当于new(Closure)
PCDATA$0,$-1
MOVQ8(SP),AX
NOP,
MOVQ$"".func·001+0(SB),BP
MOVQBP,(AX)//函数地址赋值给Closure的F部分
NOP,
MOVQ"".&i+16(SP),BP//将堆中new的变量i的地址赋值给Closure的值部分
MOVQBP,8(AX)
MOVQAX,"".~r1+40(FP)
ADDQ$24,SP
RET,

其中func·001是另一个函数的函数地址,也就是f返回的那个函数。

小结

  1. Go语言支持闭包
  2. Go语言能通过escape analyze识别出变量的作用域,自动将变量在堆上分配。将闭包环境变量在堆上分配是Go实现闭包的基础。
  3. 返回闭包时并不是单纯返回一个函数,而是返回了一个结构体,记录下函数返回地址和引用的环境中的变量地址。

tiancaiamao.gitbooks.io/go-internals/content/zh/03.6.html

责任编辑:haq
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表德赢Vwin官网 网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 语言
    +关注

    关注

    1

    文章

    97

    浏览量

    24242
  • 函数
    +关注

    关注

    3

    文章

    4327

    浏览量

    62567

原文标题:Golang 闭包的实现

文章出处:【微信号:LinuxHub,微信公众号:Linux爱好者】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    霍尔元件常开和常怎么区分

    霍尔元件是一种基于霍尔效应的磁传感器,它通过感应磁场的变化来输出相应的电信号。在讨论如何区分霍尔元件的常开和常之前,我们需要了解一些基本概念。霍尔元件一般有NPN和PNP两种输出类型,而常开和常
    的头像 发表于 12-18 10:08 77次阅读

    深入理解C语言:循环语句的应用与优化技巧

    能让你的代码更加简洁明了,还能显著提升程序执行效率。本文将详细介绍C语言中的三种常见循环结构——while循环、for循环和do...while循环,带你深入理解它
    的头像 发表于 12-07 01:11 100次阅读
    深入理解C<b class='flag-5'>语言</b>:循环语句的应用与优化技巧

    在学习go语言的过程踩过的坑

    作为一个5年的phper,这两年公司和个人都在顺应技术趋势,新项目慢慢从php转向了go语言,从2021年到现在,笔者手上也先后开发了两个go项目。在学习go
    的头像 发表于 11-11 09:22 156次阅读

    C语言中的socket编程基础

    Socket编程简介 Socket是一种通信机制,允许程序之间进行通信。在C语言中,socket编程是网络编程的基础。通过使用socket,程序可以发送和接收数据,实现不同计算机之间的通信
    的头像 发表于 11-01 16:51 299次阅读

    go语言如何解决并发问题

    作为一个后端开发,日常工作中接触最多的两门语言就是PHP和GO了。无可否认,PHP确实是最好的语言(手动狗头哈哈),写起来真的很舒爽,没有任何心智负担,字符串和整型压根就不用区分,开发速度真的是比
    的头像 发表于 10-23 13:38 132次阅读
    <b class='flag-5'>go</b><b class='flag-5'>语言</b>如何解决并发问题

    c语言中从左到右结合怎么看

    在C语言中,操作符的结合性(Associativity)是指当操作符在表达式中连续出现时,它们如何与操作数结合的顺序。对于大多数二元操作符(即需要两个操作数的操作符),C语言遵循两种基本的结合方式
    的头像 发表于 08-20 11:42 843次阅读

    三十分钟入门基础Go Java小子版

    前言 Go语言定义 Go(又称 Golang)是 Google 的 Robert Griesemer,Rob Pike 及 Ken Thompson 开发的一种静态、强类型、编译型语言
    的头像 发表于 08-12 14:32 717次阅读
    三十分钟入门基础<b class='flag-5'>Go</b> Java小子版

    技术干货驿站 ▏深入理解C语言:基本数据类型和变量

    在C语言中,数据类型和变量是编程的基础,也是理解更复杂概念的关键。数据类型决定了变量的内存分配、存储范围和操作方式,而变量则是存储数据的容器。本篇文章将从基本数据类型和变量两个方面,带你深入了解C
    的头像 发表于 07-26 17:53 2087次阅读
    技术干货驿站 ▏深入理解C<b class='flag-5'>语言</b>:基本数据类型和变量

    关于go中接口类型的表示方法

    go是一个静态性语言,每个变量都有静态的类型,因此每个变量在编译阶段中有明确的变量类型,比如像:int、float32、MyType。
    的头像 发表于 04-28 10:13 362次阅读

    Go语言中的函数、方法与接口详解

    Go 没有类,不过可以为结构体类型定义方法。方法就是一类带特殊的接收者参数的函数。方法接收者在它自己的参数列表内,位于 func 关键字和方法名之间。(非结构体类型也可以定义方法)
    的头像 发表于 04-23 16:21 820次阅读

    这个多语言包 怎么搜不到

    大家好,这个多语言包怎么搜不到 seven language lib 谁有离线不 感谢分享,
    发表于 03-24 10:06

    C语言中的typedef的应用

    C 语言提供了 typedef 关键字,您可以使用它来为类型取一个新的名字。下面的实例为单字节数字定义了一个术语 BYTE。
    发表于 03-06 11:34 380次阅读
    C<b class='flag-5'>语言中</b>的typedef的应用

    介绍C语言中错误处理和异常处理的一些常用的方法和策略

    C语言是一种低级的、静态的、结构化的编程语言,它没有提供像C++或Java等高级语言中的异常处理机制,例如try-catch-finally等。
    的头像 发表于 02-28 14:25 615次阅读

    如何解决C语言中的“访问权限冲突”异常?C语言引发异常原因分析

    如何解决C语言中的“访问权限冲突”异常?C语言引发异常原因分析  在C语言中,访问权限冲突异常通常是由于尝试访问未授权的变量、函数或其他数据结构而引起的。这种异常是编程中常见的错误之一,但是可以通过
    的头像 发表于 01-12 16:03 5605次阅读

    语言模型使用指南

    在信息爆炸的时代,我们渴望更智能、更高效的语言处理工具。GPT-3.5等大语言模型的崛起为我们提供了前所未有的机会。这不仅是技术的进步,更是人与机器共舞的一幕。本篇文章将带你走进这个奇妙的语言
    的头像 发表于 12-29 14:18 668次阅读