Golang实现延迟调用的项目实践

 更新时间:2025年02月17日 11:21:39   作者:LuckyLay  
本文主要介绍了Golang实现延迟调用的项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

延迟调用

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

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

1. 延迟调用

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

1.1 使用场景

  • 资源清理:如关闭文件、网络连接等。
  • 解锁互斥锁:在访问共享资源后,确保互斥锁被释放。
  • 打印调试信息:在函数结束时打印一些调试信息或日志。

1.2 示例

func DeferDemo() {
	num := 100
	num += 200
	// 延迟调用
	// 但是num的值是该函数调用位置计算的
	defer printMessage(num)
	num += 5
	fmt.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 zero

goroutine 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() {
			// 捕获任何可能的panic
			if 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_demo

import "fmt"

func DeferDemo() {
	num := 100
	num += 200
	// 延迟调用
	// 但是num的值是该函数调用位置计算的
	defer printMessage(num)
	num += 5
	fmt.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() {
			// 捕获任何可能的panic
			if 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_demo

import "testing"

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

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

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

到此这篇关于Golang实现延迟调用的项目实践的文章就介绍到这了,更多相关Golang 延迟调用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Golang判断两个链表是否相交的方法详解

    Golang判断两个链表是否相交的方法详解

    这篇文章主要为大家详细介绍了如何通过Golang判断两个链表是否相交,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-03-03
  • golang中的container/heap包使用

    golang中的container/heap包使用

    Golang中的container/heap包提供堆操作,适用于实现了heap.Interface的类型,本文主要介绍了golang中的container/heap包使用,感兴趣的可以了解一下
    2025-02-02
  • golang recover函数使用中的一些坑解析

    golang recover函数使用中的一些坑解析

    这篇文章主要为大家介绍了golang recover函数使用中的一些坑解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • Golang实现加权轮询负载均衡算法

    Golang实现加权轮询负载均衡算法

    加权轮询负载均衡算法是一种常见的负载均衡策略,本文主要介绍了Golang实现加权轮询负载均衡算法,具有一定的参考价值,感兴趣的可以了解一下
    2024-08-08
  • 源码解析gtoken替换jwt实现sso登录

    源码解析gtoken替换jwt实现sso登录

    这篇文章主要为大家介绍了源码解析gtoken替换jwt实现sso登录的示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • Go语言单控制器和多控制器使用详解

    Go语言单控制器和多控制器使用详解

    这篇文章主要为大家详细介绍了Go语言单控制器和多控制器的使用方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-07-07
  • Go语言中使用flag包对命令行进行参数解析的方法

    Go语言中使用flag包对命令行进行参数解析的方法

    这篇文章主要介绍了Go语言中使用flag包对命令行进行参数解析的方法,文中举了一个实现flag.Value接口来自定义flag的例子,需要的朋友可以参考下
    2016-04-04
  • Golang语言如何读取http.Request中body的内容

    Golang语言如何读取http.Request中body的内容

    这篇文章主要介绍了Golang语言如何读取http.Request中body的内容问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-03-03
  • golang中gin框架接入jwt使用token验证身份

    golang中gin框架接入jwt使用token验证身份

    本文主要介绍了golang中gin框架接入jwt使用token验证身份,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • Go语言排序算法之插入排序与生成随机数详解

    Go语言排序算法之插入排序与生成随机数详解

    从这篇文章开始将带领大家学习Go语言的经典排序算法,比如插入排序、选择排序、冒泡排序、希尔排序、归并排序、堆排序和快排,二分搜索,外部排序和MapReduce等,本文将先详细介绍插入排序,并给大家分享了go语言生成随机数的方法,下面来一起看看吧。
    2017-11-11

最新评论