iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >Go中闭包的底层原理是什么
  • 635
分享到

Go中闭包的底层原理是什么

2023-06-25 11:06:25 635人浏览 八月长安
摘要

这篇文章将为大家详细讲解有关Go中闭包的底层原理是什么,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1. 什么是闭包?一个函数内引用了外部的局部变量,这种现象,就称之为闭包。例如下面的这段代码中,adde

这篇文章将为大家详细讲解有关Go中闭包的底层原理是什么,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

1. 什么是闭包?

一个函数内引用了外部的局部变量,这种现象,就称之为闭包。

例如下面的这段代码中,adder 函数返回了一个匿名函数,而该匿名函数中引用了 adder 函数中的局部变量 sum ,那这个函数就是一个闭包。

package main  import "fmt"  func adder() func(int) int {     sum := 0     return func(x int) int {         sum += x         return sum     } }

而这个闭包中引用的外部局部变量并不会随着 adder 函数的返回而被从栈上销毁。

我们尝试着调用这个函数,发现每一次调用,sum 的值都会保留在 闭包函数中以待使用。

func main() {      valueFunc:= adder()      fmt.Println(valueFunc(2))     // output: 2      fmt.Println(valueFunc(2))   // output: 4 }

2. 复杂的闭包场景

写一个闭包是比较容易的事,但单单会写简单的闭包函数,还远远不够,如果不搞清楚闭包真正的原理,那很容易在一些复杂的闭包场景中对函数的执行逻辑进行误判。

别的不说,就拿下来这个例子来说吧?

你觉得它会打印什么呢?

是 6 还是 11 呢?

import "fmt"  func func1() (i int) {     i = 10     defer func() {         i += 1     }()     return 5 }  func main() {     closure := func1()     fmt.Println(closure) }

3. 闭包的底层原理?

还是以最上面的例子来分析

package main  import "fmt"  func adder() func(int) int {     sum := 0     return func(x int) int {         sum += x         return sum     } }  func main() {     valueFunc:= adder()     fmt.Println(valueFunc(2))     // output: 2 }

我们先对它进行逃逸分析,很容易发现 sum 作为 adder 函数局部变量,并不是分配在栈上,而是分配在堆上的。

这就解决了第一个疑惑:为什么 adder 函数返回后, sum 不会随之销毁?

$ go build -GCflags="-m -m -l" demo.go # command-line-arguments ./demo.go:8:3: adder.func1 capturing by ref: sum (addr=true assign=true width=8) ./demo.go:7:9: func literal escapes to heap: ./demo.go:7:9:   flow: ~r0 = &{storage for func literal}: ./demo.go:7:9:     from func literal (spill) at ./demo.go:7:9 ./demo.go:7:9:     from return func literal (return) at ./demo.go:7:2 ./demo.go:6:2: sum escapes to heap: ./demo.go:6:2:   flow: {storage for func literal} = &sum: ./demo.go:6:2:     from func literal (captured by a closure) at ./demo.go:7:9 ./demo.go:6:2:     from sum (reference) at ./demo.go:8:3 ./demo.go:6:2: moved to heap: sum ./demo.go:7:9: func literal escapes to heap ./demo.go:15:23: valueFunc(2) escapes to heap: ./demo.go:15:23:   flow: {storage for ... argument} = &{storage for valueFunc(2)}: ./demo.go:15:23:     from valueFunc(2) (spill) at ./demo.go:15:23 ./demo.go:15:23:   flow: {heap} = {storage for ... argument}: ./demo.go:15:23:     from ... argument (spill) at ./demo.go:15:13 ./demo.go:15:23:     from fmt.Println(valueFunc(2)) (call parameter) at ./demo.go:15:13 ./demo.go:15:13: ... argument does not escape ./demo.go:15:23: valueFunc(2) escapes to heap

可另一个问题,又浮现出来了,就算它不会销毁,那闭包函数若是存储的若是 sum 拷贝后的值,那每次调用闭包函数,里面的 sum 应该都是一样的,调用两次都应该返回 2,而不是可以累加记录。

因此,可以大胆猜测,闭包函数的结构体里存储的是 sum 的指针。

为了验证这一猜想,只能上汇编了。

通过执行下面的命令,可以输出对应的汇编代码

go build -gcflags="-S" demo.go

输出的内容相当之多,我提取出下面最关键的一行代码,它定义了闭包函数的结构体。

其中 F 是函数的指针,但这不是重点,重点是 sum 存储的确实是指针,验证了我们的猜。

type.noalg.struct { F uintptr; "".sum *int }(SB), CX

4. 迷题揭晓

有了上面第三节的背景知识,那对于第二节给出的这道题,想必你也有答案了。

首先,由于 i 在函数定义的返回值上声明,因此根据 go 的 caller-save 模式, i 变量会存储在 main 函数的栈空间。

然后,func1 return 重新把 5 赋值给了 i ,此时 i = 5

由于闭包函数存储了这个变量 i 的指针。

因此最后,在 defer 中对 i 进行自增,是直接更新到 i 的指针上,此时 i = 5+1,所以最终打印出来的结果是 6

import "fmt"  func func1() (i int) {     i = 10     defer func() {         i += 1     }()     return 5 }  func main() {     closure := func1()     fmt.Println(closure) }

5. 再度变题

上面那题听懂了的话,再来看看下面这道题。

func1 的返回值我们不写变量名 i 了,然后原先返回具体字面量,现在改成变量 i ,就是这两小小小的改动,会导致运行结果大大不同,你可以思考一下结果。

import "fmt"  func func1() (int) {     i := 10     defer func() {         i += 1     }()     return i }  func main() {     closure := func1()     fmt.Println(closure) }

如果你在返回值里写了变量名,那么该变量会存储 main 的栈空间里,而如果你不写,那 i 只能存储在 func1 的栈空间里,与此同时,return 的值,不会作用于原变量 i 上,而是会存储在该函数在另一块栈内存里。

因此你在 defer 中对原 i 进行自增,并不会作用到 func1 的返回值上。

所以打印的结果,只能是 10。

你答对了吗?

关于“Go中闭包的底层原理是什么”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

--结束END--

本文标题: Go中闭包的底层原理是什么

本文链接: https://www.lsjlt.com/news/304116.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Go中闭包的底层原理是什么
    这篇文章将为大家详细讲解有关Go中闭包的底层原理是什么,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1. 什么是闭包一个函数内引用了外部的局部变量,这种现象,就称之为闭包。例如下面的这段代码中,adder...
    99+
    2023-06-25
  • Go 中闭包的底层原理
    目录1. 什么是闭包?2. 复杂的闭包场景3. 闭包的底层原理?4. 迷题揭晓5. 再度变题6. 最后一个问题1. 什么是闭包? 一个函数内引用了外部的局部变...
    99+
    2024-04-02
  • Go 中函数类型的底层原理是什么?
    go 中的函数类型是一个具有输入参数类型和输出返回类型的元组。函数类型可以作为值或引用传递,默认情况下作为值传递,显式作为引用传递需要使用 *。在实战中,函数类型可用于创建可重用的函数,...
    99+
    2024-04-19
    底层原理 函数类型
  • go语言中slice,map,channl底层原理是什么
    今天小编给大家分享一下go语言中slice,map,channl底层原理是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。...
    99+
    2023-06-30
  • linux中mutex的底层原理是什么
    在Linux中,mutex的底层原理主要是基于原子操作和内核态的同步机制来实现的。 具体来说,Linux中的mutex通常是通过sp...
    99+
    2024-03-15
    linux
  • Java中LinkedHashMap 的底层原理是什么
    本篇文章为大家展示了Java中LinkedHashMap 的底层原理是什么,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。默认情况下,LinkedHashMap的迭代顺序是按照插入节点的顺序。也可以通...
    99+
    2023-06-15
  • InnoDB底层原理是什么
    这篇文章主要为大家展示了“InnoDB底层原理是什么”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“InnoDB底层原理是什么”这篇文章吧。InnoDB,是MySQL的数据库引擎之一,现为MySQ...
    99+
    2023-06-27
  • Spring底层原理是什么
    这篇文章主要讲解了“Spring底层原理是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Spring底层原理是什么”吧!Spring简介ClassPathXmlApplicationCo...
    99+
    2023-07-05
  • Docker的底层原理是什么
    Docker的底层原理是什么,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。Docker 能实现这些功能,依赖于 chroot、namespac...
    99+
    2024-04-02
  • HashMap的底层原理是什么
    这篇文章将为大家详细讲解有关HashMap的底层原理是什么,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。一:HashMap的节点:HashMap是一个集合,键值对的集合,源码中每个节点用No...
    99+
    2023-06-04
  • java中CAS的底层原理是什么
    今天就跟大家聊聊有关java中CAS的底层原理是什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。常用的java框架有哪些1.SpringMVC,Spring Web MVC是一种基...
    99+
    2023-06-14
  • HashMap底层原理是什么
    本篇内容介绍了“HashMap底层原理是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!HashMap存...
    99+
    2024-04-02
  • zookeeper底层原理是什么
    Zookeeper是一个开源的分布式协调服务,用于构建分布式系统中的一些基本功能,如配置管理、分布式锁、领导者选举等。其底层原理主要...
    99+
    2024-04-02
  • redis的底层原理是什么
    这篇文章主要介绍“redis的底层原理是什么”,在日常操作中,相信很多人在redis的底层原理是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”redis的底层原理是什么”...
    99+
    2024-04-02
  • Vue的底层原理是什么
    这篇文章主要介绍Vue的底层原理是什么,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!Observer (数据劫持)核心是通过Obeject.defineProperty()来监听数据的变动,这个函数内部可以定义set...
    99+
    2023-06-29
  • Spring Boot的底层原理是什么
    这篇文章主要讲解了“Spring Boot的底层原理是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Spring Boot的底层原理是什么”吧!1.基于你对springboot的理解描述...
    99+
    2023-06-27
  • python 中GIL锁的底层原理是什么
    这篇文章将为大家详细讲解有关python 中GIL锁的底层原理是什么,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。python可以做什么Python是一种编程语言,内置了许多有效的工具,Py...
    99+
    2023-06-14
  • Python matplotlib底层原理是什么
    本篇内容介绍了“Python matplotlib底层原理是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1. matplot...
    99+
    2023-06-21
  • Java NIO底层原理是什么
    这篇文章主要介绍“Java NIO底层原理是什么”,在日常操作中,相信很多人在Java NIO底层原理是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java NIO底层原理是什么”的疑惑有所帮助!接下来...
    99+
    2023-06-16
  • redis锁底层原理是什么
    Redis的锁底层原理是基于Redis的单线程特性和原子操作来实现的。当一个客户端尝试获取锁时,它会向Redis发送一个SETNX命...
    99+
    2023-09-06
    redis
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作