Golang学习笔记_05——延迟调用

Golang学习笔记_02——函数
Golang学习笔记_03——匿名函数和闭包
Golang学习笔记_04——递归函数


文章目录

    • 延迟调用
      • 1. 延迟调用
        • 1.1 使用场景
        • 1.2 示例
      • 2. panic
        • 2.1 使用场景
        • 2.2 示例
      • 3. recover
        • 3.1 使用场景
        • 3.2 示例
    • 源码


延迟调用

在Go语言中,延迟调用(defer)是一个非常重要的特性,它允许你安排一个函数在当前函数执行完毕后被执行,无论是否发生panic。

这通常用于资源清理、文件关闭、解锁互斥锁等操作。

1. 延迟调用

defer语句会将一个函数推迟到包含该defer语句的函数即将返回时执行。推迟执行的函数其参数会立即求值,但函数本身会延迟到外围函数返回前才执行。

1.1 使用场景
  1. 资源清理:如关闭文件、网络连接等。
  2. 解锁互斥锁:在访问共享资源后,确保互斥锁被释放。
  3. 打印调试信息:在函数结束时打印一些调试信息或日志。
1.2 示例
func DeferDemo() {num := 100num += 200// 延迟调用// 但是num的值是该函数调用位置计算的defer printMessage(num)num += 5fmt.Println(num)
}func printMessage(num int) {fmt.Println("printMessage func")fmt.Println("i am in defer: ", num)
}

测试方法

func TestDeferDemo(t *testing.T) {DeferDemo()
}

输出结果

=== RUN   TestDeferDemo
305
printMessage func
i am in defer:  300
--- PASS: TestDeferDemo (0.00s)
PASS

2. panic

panic是一个内置函数,当程序运行时遇到无法恢复的错误时,可以调用panic函数。

它会立即中断当前函数的执行,并开始逐层向上执行已注册的延迟调用(defer语句)。

在延迟调用执行完毕后,程序会崩溃并打印出传递给panic函数的值。

2.1 使用场景

panic通常用于处理严重的运行时错误,如数组越界、空指针引用等。

2.2 示例
func panicDemo() {divide_func := func(a, b int) int {if b == 0 {panic("divide by zero")}return a / b}defer printMessage(1)divide_func(1, 0)fmt.Println("不会被执行")
}

测试方法

func Test_panicDemo(t *testing.T) {panicDemo()
}

输出结果

=== RUN   Test_panicDemo
printMessage func
i am in defer:  1
--- FAIL: Test_panicDemo (0.00s)
panic: divide by zero [recovered]panic: divide by zerogoroutine 3 [running]:
testing.tRunner.func1.2({0x1042b9dc0, 0x1042e3860})
……

3. recover

recover是一个内置函数,它用于从panic中恢复。

recover只有在延迟调用的函数中调用时才有用。

在正常的执行流程中调用recover会返回nil,并且不会有任何效果。

如果在延迟调用的函数中调用了recover,并且其所在的函数是由于panic而正在退出,那么recover会捕获到传递给panic的值,并且阻止程序的崩溃。此时,程序会继续执行从panic点之后的代码(如果有的话)。

3.1 使用场景

recover通常用于在可能引发panic的代码块周围添加额外的错误处理逻辑,以允许程序在发生严重错误时优雅地恢复。

3.2 示例
func recoverDemo() {divideFunc := func(a, b int) int {if b == 0 {panic("divide by zero")}return a / b}saveDivideFunc := func() (int, error) {defer func() {// 捕获任何可能的panicif r := recover(); r != nil {fmt.Println("Recovered from panic:", r)}}()// 尝试执行可能引发panic的操作result := divideFunc(10, 0)// 如果没有panic发生,则返回结果return result, nil}divideRes, err := saveDivideFunc()if err != nil {fmt.Println(err)} else {fmt.Println(divideRes)}
}

测试方法

func Test_recoverDemo(t *testing.T) {recoverDemo()
}

输出结果

=== RUN   Test_recoverDemo
Recovered from panic: divide by zero
0
--- PASS: Test_recoverDemo (0.00s)
PASS

源码

// defer_demo.go 文件
package function_demoimport "fmt"func DeferDemo() {num := 100num += 200// 延迟调用// 但是num的值是该函数调用位置计算的defer printMessage(num)num += 5fmt.Println(num)
}func printMessage(num int) {fmt.Println("printMessage func")fmt.Println("i am in defer: ", num)
}func panicDemo() {divideFunc := func(a, b int) int {if b == 0 {panic("divide by zero")}return a / b}defer printMessage(1)divideFunc(1, 0)fmt.Println("不会被执行")}func recoverDemo() {divideFunc := func(a, b int) int {if b == 0 {panic("divide by zero")}return a / b}saveDivideFunc := func() (int, error) {defer func() {// 捕获任何可能的panicif r := recover(); r != nil {fmt.Println("Recovered from panic:", r)}}()// 尝试执行可能引发panic的操作result := divideFunc(10, 0)// 如果没有panic发生,则返回结果return result, nil}divideRes, err := saveDivideFunc()if err != nil {fmt.Println(err)} else {fmt.Println(divideRes)}
}
package function_demoimport "testing"func TestDeferDemo(t *testing.T) {DeferDemo()
}func Test_panicDemo(t *testing.T) {panicDemo()
}func Test_recoverDemo(t *testing.T) {recoverDemo()
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/63197.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

防范TCP攻击:策略与实践

TCP(传输控制协议)是互联网通信的核心协议之一,它确保了数据在网络上的可靠传输。然而,TCP也容易成为各种网络攻击的目标,如SYN洪水攻击、TCP连接耗尽攻击等。本文将探讨如何通过配置防火墙规则、优化服务器设置以及采…

水表的数字表盘分割数据集labelme格式3023张13类别

数据集格式:labelme格式(不包含mask文件,仅仅包含jpg图片和对应的json文件) 图片数量(jpg文件个数):3023 标注数量(json文件个数):3023 标注类别数:13 标注类别名称:["readbox_1","center",&q…

【go语言】reflect包与类型推断

reflect 包的核心概念 Go 中的反射涉及两个核心概念: Type:表示一个类型的结构体,reflect.Type 是类型的描述。Value:表示一个值的结构体,reflect.Value 是一个具体值的包装。 反射让我们能够动态地访问对象的类型和…

跟着AI 学 AI, 开发一个ChatBot, 集成 Json 数据和查询

按照规律,使用AI生成一个架构图 直接上代码,为了方便学习,直接按照如下方式,复制到你的开发环境即可调试,运行代码。做学习参考。 代码注释多次说明这里,不在赘述。 "type": "carousel&qu…

WPF+MVVM案例实战与特效(三十七)- 实现带有水印和圆角的自定义 TextBox 控件

文章目录 1、概述2、案例实现1、基本功能2、代码实现3、控件应用4、案例效果4、总结1、概述 在开发用户界面时,TextBox 是最常见的输入控件之一。为了提升用户体验,我们经常需要为 TextBox 添加一些额外的功能,例如显示提示文本(水印)和设置圆角边框。本文将详细介绍如何…

使用枚举实现单例模式,不会反序列化破坏攻击,不会被反射破坏攻击。(附带枚举单例的简单实现)

原因分析 1.反序列化方法 ① jdk8中的Enum源码中对反序列化方法进行重写,抛出异常。 java.lang.Enum#readObject方法截图如下 ②java.io.ObjectInputStream#readObject 方法中的 readEnum 方法处理了枚举类型的反序列化,从而确保了枚举的单例特性。 …

Linux下的守护程序

启动流程 嵌入式设备下Linux的内核系统启动的流程并不复杂,从最早的父进程init开始,为创建各种服务进程:系统会从 inittab 文件中,读取每一行作为执行命令👇 # Note: BusyBox init doesnt support runlevels. The r…

2024第十六届蓝桥杯模拟赛(第二期)-Python

# 2024第十六届蓝桥杯模拟赛&#xff08;第二期&#xff09;-Python题解 # 自己改注释# -----------------------1------------------------ # def prime(x): # if x < 2: # return 0 # for i in range(2, int(x ** 0.5) 1): # if x % i 0: # …

MongoDB-副本集

一、什么是 MongoDB 副本集&#xff1f; 1.副本集的定义 MongoDB 的副本集&#xff08;Replica Set&#xff09;是一组 MongoDB 服务器实例&#xff0c;它们存储同一数据集的副本&#xff0c;确保数据的高可用性和可靠性。副本集中的每个节点都有相同的数据副本&#xff0c;但…

《数据结构》(408代码题)

2009 单链表&#xff08;双指针&#xff09; 分析&#xff1a;首先呢&#xff0c;给我们的数据结构是一个带有表头结点的单链表&#xff0c;也不允许我们改变链表的结构。链表的长度不是直接给出的啊&#xff0c;所以这个倒数也很棘手。那我们该如何解决这个“k”呢&#xff0c…

6.1 初探MapReduce

MapReduce是一种分布式计算框架&#xff0c;用于处理大规模数据集。其核心思想是“分而治之”&#xff0c;通过Map阶段将任务分解为多个简单任务并行处理&#xff0c;然后在Reduce阶段汇总结果。MapReduce编程模型包括Map和Reduce两个阶段&#xff0c;数据来源和结果存储通常在…

Cad c#.net 一键修改标注dimension中的文本内容

本例为给标注加前缀&#xff0c;也可定制其他形式&#xff0c;效果如下&#xff1a; public class Demo{[CommandMethod("xx")]//public void Dim(){Document doc Application.DocumentManager.MdiActiveDocument;Database db doc.Database;Editor ed doc.Editor;…

Scala的隐式类

package hfd //隐式类 //任务&#xff1a;给之前的BaseUser添加新的功能&#xff0c;但是不要直接去改代码 //思路&#xff1a;把BaseUser通过隐式转换&#xff0c;改成一个新类型&#xff0c;而这个新类型中有这新的方法 //implicit class一个隐式转换函数类 //作用&#xff1…

旅游系统旅游小程序PHP+Uniapp

旅游门票预订系统&#xff0c;支持景点门票、导游产品便捷预订、美食打卡、景点分享、旅游笔记分享等综合系统 更新日志 V1.3.0 1、修复富文本标签 2、新增景点入驻【高级版本】3、新增门票核销【高级版】4、新增门票端口【高级版】

MacOS系统 快速安装appium 步骤详解

在macOS系统上&#xff0c;你可以通过使用nvm&#xff08;Node Version Manager&#xff09;来管理Node.js的版本&#xff0c;并基于nvm安装的Node.js环境来快捷地安装Appium。以下是具体步骤&#xff1a; 一、安装nvm 下载nvm 访问nvm的GitHub仓库&#xff08;nvm GitHub&…

模型训练中梯度累积步数(gradient_accumulation_steps)的作用

模型训练中梯度累积步数&#xff08;gradient_accumulation_steps&#xff09;的作用 flyfish 在使用训练大模型时&#xff0c;TrainingArguments有一个参数梯度累积步数&#xff08;gradient_accumulation_steps&#xff09; from transformers import TrainingArguments梯…

技术速递|.NET 9 简介

作者&#xff1a;.NET 团队 排版&#xff1a;Alan Wang 今天&#xff0c;我们非常激动地宣布 .NET 9的发布&#xff0c;这是迄今为止最高效、最现代、最安全、最智能、性能最高的 .NET 版本。这是来自世界各地数千名开发人员又一年努力的成果。这个新版本包括数千项性能、安全和…

Vue项目打包部署到服务器

1. Vue项目打包部署到服务器 1.1. 配置 &#xff08;1&#xff09;修改package.json文件同级目录下的vue.config.js文件。 // vue.config.js module.exports {publicPath: ./, }&#xff08;2&#xff09;检查router下的index.js文件下配置的mode模式。   检查如果模式改…

【jpa】springboot使用jpa示例

目录 1. 请求示例2. pom依赖3. application.yaml4.controller5. service6. repository7. 实体8. 启动类 1. 请求示例 curl --location --request POST http://127.0.0.1:8080/user \ --header User-Agent: Apifox/1.0.0 (https://apifox.com) \ --header Content-Type: applic…

uniapp 常用的指令语句

uniapp 是一个使用 Vue.js 开发的跨平台应用框架&#xff0c;因此&#xff0c;它继承了 Vue.js 的大部分指令。以下是一些在 uniapp 中常用的 Vue 指令语句及其用途&#xff1a; v-if / v-else-if / v-else 条件渲染。v-if 有条件地渲染元素&#xff0c;v-else-if 和 v-else 用…