首页 > 其他分享 >Go中的闭包和defer关键字

Go中的闭包和defer关键字

时间:2024-01-15 14:58:46浏览次数:24  
标签:闭包 defer int fmt result func Go

闭包基本介绍:
闭包就是一个函数和与其相关的引用环境组合的一个整体。

package main

import "fmt"
func main() {
	//使用AddUpper函数
    //当反复调用f函数,因为n是初始化一次,因此每调用一次就进行累计。
    //我们要搞清楚闭包的关键,就是要分析出返回的函数引用到了哪些变量,因为函数和它引用的变量共同构成闭包。
	f := AddUpper()
	result := f(1)//第一次n是10  那么结果就是10+1=11
	fmt.Println("result", result)//11 
	result2 := f(2)//里面的n已经是11了 那么结果是11+2=13
	fmt.Println("result2", result2)//13
}
//AddUpper是一个函数返回的数据类型是:func(int) int
func AddUpper() func(int) int {
    //闭包的说明:返回的是一个匿名函数,这个匿名函数引用到了函数外的n,因此这个匿名函数就和n就形成一个整体构成了闭包。
    //可以这样理解:闭包是一个类,函数是操作,n是字段。函数和它使用到的n构成闭包
	var n int = 10
	return func(x int) int {
		n = n + x
		return n
	}
}

加深对闭包理解:

package main

import (
	"fmt"
	"strconv"
)

func main() {
	//使用AddUpper函数
	f := AddUpper()
	result := f(1)
	fmt.Println("result", result)   // str= hello11  result 11 
	result2 := f(2)                 //里面的n已经是11了 那么结果是11+2=13
	fmt.Println("result2", result2) //str= hello1113 result2 13
}

func AddUpper() func(int) int {
	var n int = 10
	var str string = "hello"
	return func(x int) int {
		n = n + x
		str = str + strconv.Itoa(n) //str = hello+n
		fmt.Println("str=", str)
		return n
	}
}

闭包的案例:

package main

import (
	"fmt"
	"strings"
)
func main() {
  	a := makeSuffix(".jpg")
	result3 := a("mafu")
	fmt.Println("result3", result3) //mafu.jpg
	result4 := a("haha.jpg")
	fmt.Println("result4", result4) //haha.jpg
}
//传入一个后缀,判断这个一个文件名是否包含次后缀,如果包含直接返回该文件名,不包含就加上。
//返回的匿名函数和makeSuffix(suffix string)中的suffix变量组成一个闭包,因为返回的函数引用到了suffix变量。
func makeSuffix(suffix string) func(name string) string {
	return func(name string) string {
		if !strings.HasSuffix(name, suffix) {
			//如果name没有指定的后缀suffix。则加上
			return name + suffix
		}
		//有后缀则直接返回
		return name
	}
}

闭包的好处:如果使用传统方法,也可以完成这个需求,但是传统的方法需要每一次都传入后缀,比如.jpg。而闭包因为可以保留上次引用的某个值。所以我们传入一次就可以反复使用了。

defer关键字:
为了在函数执行完毕后,及时释放资源。Go中提供defer(延时机制)

package main

import "fmt"

func main() {
	//当sum函数执行完毕后再执行defer栈中的代码。
	res := sum(1, 2)
	fmt.Println("res=", res) //第四  res=3
}

func sum(n1 int, n2 int) int {
	//当执行到defer时,会将defer语句压入到独立的栈中(defer栈)
	defer fmt.Println("ok1 n1=", n1) //第三 ok1 n1=1
	//当执行到defer时,会将defer语句压入到独立的栈中(defer栈) 栈是先进后出 所以这句语句后进先出来
	defer fmt.Println("ok2 n2=", n2) //第二 ok2 n2=2
	result := n1 + n2
	fmt.Println("ok3 result=", result) //第一  result=3
	return result
}

细节说明:

  1. 当go执行到一个defer时,不会立即执行defer后的语句,而是将defer后的语句压入到一个栈中,然后继续执行函数的下一条语句。

  2. 当函数执行完毕后,在从defer栈中,依次从栈顶取出语句执行(先进后出)

  3. 在defer将语句放入栈时,也会将相关的值拷贝同时入栈。

func sum(n1 int, n2 int) int {
	//当执行到defer时,会将defer语句压入到独立的栈中(defer栈)
	defer fmt.Println("ok1 n1=", n1) //第三 ok1 n1=1  后面n1虽然自增+1 但是对栈中的n1没有影响 因为值拷贝
	//当执行到defer时,会将defer语句压入到独立的栈中(defer栈) 栈是先进后出 所以这句语句后进先出来
	defer fmt.Println("ok2 n2=", n2) //第二 ok2 n2=2
    n1++  //2
    n2++  //3
	result := n1 + n2
	fmt.Println("ok3 result=", result) //第一  result=3
	return result
}

标签:闭包,defer,int,fmt,result,func,Go
From: https://www.cnblogs.com/mafu-blogs/p/17965026

相关文章

  • Dithered golden interleaver 黄金分割伪随机交织器 代码备份
    目录公式来源DitheredgoldeninterleaverTheMatrix-DitheredGoldenInterleavingAlgorithm有错误欢迎指正公式来源DesignofaModifiedInterleavingAlgorithmBasedonGoldenSectionTheoryEnhancingthePerformanceofTurboCodesDitheredgoldeninterleaver(*......
  • Go中init函数和匿名函数
    init函数:每一个源文件中都可以包含一个init函数,该函数会在main函数执行前,被Go运行框架调用,也就是init会在Main函数之前被调用。通常可以在init函数中完成初始化工作。import"fmt"funcmain(){ fmt.Println("main函数")//后输出}funcinit(){ fmt.Println("init方法")......
  • Redis、Memcache和MongoDB的区别
    Redis、Memcache和MongoDB的区别 >>MemcachedMemcached的优点:Memcached可以利用多核优势,单实例吞吐量极高,可以达到几十万QPS(取决于key、value的字节大小以及服务器硬件性能,日常环境中QPS高峰大约在4-6w左右)。适用于最大程度扛量。支持直接配置为sessionhandle。Memcached的......
  • Js中的闭包
    Js中的闭包APR 11TH, 2017 5:11PM闭包的概念Wikipedia:Inprogramminglanguages,closures(alsolexicalclosuresorfunctionclosures)areatechniqueforimplementinglexicallyscopednamebindinginlanguageswithfirst-classfunctions.译文:”在编程语言......
  • Go Lang 异常处理
    C#,JAVA等语言通过try...catch...finally实现错误的捕获和处理GoLang异常处理的设计思想中主张如果一个函数可能出现异常,那么应该把异常作为返回值,没有异常就返回nil每次调用可能出现异常的函数时,都应该主动进行检查,并做出反应,这种 if 卫述语句所以异常应该总是掌握在......
  • go-micro 简介
    1.go-micro简介GoMicro是一个插件化的基础框架,基于此可以构建微服务,Micro的设计哲学是可插拔的插件化架构在架构之外,它默认实现了consul作为服务发现(2019年源码修改了默认使用mdns),通过http进行通信,通过protobuf和json进行编解码2.go-micro的主要功能服务发现:自动服务注......
  • Django 源码分析(一):命令分析
    Django源码分析(一):命令分析说明:本部分主要介绍Django程序在开发中常用的命令是如何控制生成的进行解析;1.分析入口启动命令:pythonmanage.pyrunserver127.0.0.1:8000项目启动的时候执行的manage.py脚本,相关代码如下:"""Django'scommand-lineutilityforadministrat......
  • Django 源码分析(二):wsgi & asgi
    Django源码分析(二):wsgi&asgi说明:上一节主要讲述了django项目的启动,后期主要会根据django请求的生命周期进行分析;参考文章:https://zhuanlan.zhihu.com/p/95942024参考文章:https://zhuanlan.zhihu.com/p/269456318附:生命周期参考图;第一步:浏览器发起请求补充:第一步和第......
  • Django 请求到来与路由匹配
    Django请求到来与路由匹配说明:本部分主要讲述请求到来与路由匹配的部分;1.请求到来上次分析到了wsgi的函数内部处理信息,我们已经知道请求到了之后会执行__call__方法,下面将继续分析__call__方法。classWSGIHandler(base.BaseHandler):#继承BaseHandlerrequest......
  • Django 源码(三)-应用 & 中间件 & 配置文件
    Django源码(三)-应用&中间件&配置文件本部分主要是在为程序启动时候加载应用以及中间件的信息;1.应用的加载在程序启动的部分,我们分析到程序执行的时候都会执行一个setup()函数,相关的内容可以看之前的章节的部分;defsetup(set_prefix=True):"""Configurethes......