首页 > 其他分享 >go语言的defer

go语言的defer

时间:2023-06-01 10:04:49浏览次数:55  
标签:defer 关闭 语言 err fmt Println func go

go语言的defer机制可以避免其他语言时处理错误,要在每个分支执行关闭、回收资源的繁杂问题。

百闻不如一见,看的教程再多,也不如自己实际编程,调试来得方便。

以下为根据测试代码段进行总结的过程。

1.

package main

import "fmt"

func test1() {
	fmt.Println("循环开始")
	var p *int
	for i := 0; i < 5; i++ {
		fmt.Println("i = ", i)
		defer func(i int) {
			fmt.Println("this is first defer ", i)
		}(i) //带参数
		defer func() {
			fmt.Println("this is second defer", i*10)
		}() //不带参数
		p = &i
	}
	//return	//在此处注释
	fmt.Println("循环结束")
	defer func() {
		fmt.Println("this is the last defer")
	}()
	fmt.Println("修改循环变量i指针之前 i = ", *p)
	*p = 1	//在此处注释
	fmt.Println("修改循环变量i指针之后 i = ", *p)
}
func main() {
	test1()
}

循环开始
i =  0                      
i =  1                      
i =  2                      
i =  3                      
i =  4                      
循环结束                    
修改循环变量i指针之前 i =  5
修改循环变量i指针之后 i =  1
this is the last defer      
this is second defer 10     
this is first defer  4      
this is second defer 10     
this is first defer  3      
this is second defer 10     
this is first defer  2
this is second defer 10
this is first defer  1
this is second defer 10
this is first defer  0

解释:test1()函数有两处代码注释,将其注释或者打开,可以得出以下结论。

1.defer要执行的函数或者语句,与defer语句出现的先后顺序有关系。假设你把每一个defer语句看作 stack.push(),就很容易理解defer执行的顺序了。显然,如果打开return处的注释,就不会执行return后面的defer了。

2.defer函数和普通函数一样,可以带参数,需考虑参数是值还是指针。这一点观看循环里面的输出就很好理解了。不带参数,就有对循环变量i的引用。

func test2() {
	f, _ := os.Open(`C:\Users\yyjeqhc\Desktop\bc\1.cpp`)
	defer func() {
		if err := f.Close(); err != nil {
			fmt.Println("1.cpp已经关闭")
		} else {
			fmt.Println("1.cpp在这里关闭")
		}
	}()
	var fa = func(f *os.File) {
		if err := f.Close(); err != nil {
			fmt.Println("文件已经关闭")
		} else {
			name := f.Name()
			filename := path.Base(name)
			//fmt.Println("不包含目录的文件名:", filename)
			fmt.Println("关闭了", filename)
		}
	}
	defer fa(f)
	f1, _ := os.Open(`C:\Users\yyjeqhc\Desktop\bc\1.py`)
	defer func() {
		if err := f1.Close(); err != nil {
			fmt.Println("1.py已经关闭")
		} else {
			fmt.Println("1.py在这里关闭")
		}
	}()
	defer fa(f1)
	var t = func(i int) {
		fmt.Println("this is a func and i = ", i)
		defer func() {
			fmt.Println("this is defer in a func", i)
		}()
	}
	t(1)
	fmt.Println("-----------------")
	t(2)
	fmt.Println("this is end")
}

可见输出

this is a func and i =  1
this is defer in a func 1               
-----------------                       
this is a func and i =  2               
this is defer in a func 2               
this is end                             
关闭了 C:\Users\yyjeqhc\Desktop\bc\1.py 
1.py已经关闭                            
关闭了 C:\Users\yyjeqhc\Desktop\bc\1.cpp
1.cpp已经关闭

得出结论:就算是匿名函数里面的defer,也会在匿名函数调用结束后执行。也就是defer以函数分层,每层函数都有自己的defer调用栈。

欢迎提出有趣的代码片段以加深理解。

标签:defer,关闭,语言,err,fmt,Println,func,go
From: https://www.cnblogs.com/dayq/p/17448087.html

相关文章

  • go gmp
    MGPM:machine系统线程,执行实体,通过系统调用clone来创建G:groutine任务和上下文P:虚拟处理器,M需要获得P才能执行否则休眠go的调度本质上是一个生产消费的流程生产端M负责调度循环消费task队列分runnext+本地队列+全局队列来区分优先级,也避免锁本地队列使用的数据结构是......
  • 博学谷学习记录】超强总结,用心分享 | mongodb基础用法
    【博学谷IT技术支持】数据库连接后端数据库连接语法:mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]mongodb://是固定搭配,后边是可选参数用户名加密码,host是要连接服务器的地址,portx是指定的端口,默认27017da......
  • go中的并发学习
    代码源自于https://github.com/lotusirous/go-concurrency-patterns自此对各个示例代码进行调试。1-boringpackagemainimport( "fmt" "math/rand" "time")funcboring(msgstring){ fori:=0;;i++{ fmt.Println(msg,i) time.Sleep(time.D......
  • 各个语言运行100万个并发任务需要多少内存?
    译者注:原文链接:https://pkolaczk.github.io/memory-consumption-of-async/Github项目地址:https://github.com/pkolaczk/async-runtimes-benchmarks正文在这篇博客文章中,我深入探讨了异步和多线程编程在内存消耗方面的比较,跨足了如Rust、Go、Java、C#、Python、Node.js和Elix......
  • Linux系统下C语言的编程技巧
    Linux系统能够为人们提供更加安全实用的效果,保证计算机系统能够稳定的运行。利用Linux系统下首先要进行C语言的编程,掌握编程的技巧能够更好的发挥计算机的作用。如何掌握Linux系统下计算机C语言的编程技巧是计算机发展的关键要素。本文对Linux系统下计算机C语言的编程技巧进行相......
  • R语言状态空间模型和卡尔曼滤波预测酒精死亡人数时间序列|附代码数据
    原文链接:http://tecdat.cn/?p=22665最近我们被客户要求撰写关于状态空间模型的研究报告,包括一些图形和统计输出。状态空间建模是一种高效、灵活的方法,用于对大量的时间序列和其他数据进行统计推断摘要本文介绍了状态空间建模,其观测值来自指数族,即高斯、泊松、二项、负二项和伽......
  • golang vscode开发环境配置
    1.下载go安装包并安装官网下载地址2.下载vscode并安装官网下载地址3.安装vscodego语言开发扩展(插件)4.切换国内下载源,cmd输入如下代码goenv-wGO111MODULE=ongoenv-wGOPROXY=https://goproxy.cn,direct5.安装vscodego开发工具包windows下vscodeCtrl+Shift+P找......
  • mongocxx c++ 14标准,进行多表联合查询
     #include<mongocxx/client.hpp>#include<mongocxx/instance.hpp>#include<mongocxx/uri.hpp>#include<bsoncxx/builder/stream/document.hpp>#include<bsoncxx/json.hpp>#include<bsoncxx/types.hpp>usingbsoncxx::builder::s......
  • mongodb安装
    一、YUM安装MongoDB1、添加一个yum源创建一个/etc/yum.repos.d/mongodb-org-5.0.repo文件[mongodb-org-5.0]name=MongoDBRepositorybaseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/5.0/x86_64/gpgcheck=1enabled=1gpgkey=https://www.mongodb.or......
  • 如何使用Go中的Weighted实现资源管理
    1.简介本文将介绍Go语言中的Weighted并发原语,包括Weighted的基本使用方法、实现原理、使用注意事项等内容。能够更好地理解和应用Weighted来实现资源的管理,从而提高程序的稳定性。2.问题引入在微服务架构中,我们的服务节点负责接收其他节点的请求,并提供相应的功能和数......