目录
- 延迟调用
- 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 示例
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
305printMessage funci am in defer: 300--- PASS: TestDeferDemo (0.00s)PASS
2. panic
panic是一个内置函数,当程序运行时遇到无法恢复的错误时,可以调用panic函数。
它会立即中断当前函数的执行,并开始逐层向上执行已注册的延迟调用(defer语句)。
在延迟调用执行完毕后,程序会崩溃并打印出传递给panic函数的值。
2.1 使用场景
panic通常用于处理严重的运行时错误,如数组越界、空指针引用等。
2.2 示例
func panicDemo() {
divide_func python:= func(a, b int) int {
if b == 0 {
panic("divi编程客栈de 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 funci 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() {
// 捕获任何可能的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.Pphprintln(divideRes)
}
}
测试方法
func Test_recoverDemo(t *testing.T) {
recoverDemo()
}
输出结果
=== RUN Test_recoverDemo
Recovered from panic: divide by zero0--- PASS: Test_recoverDemo (0.00s)PASS
源码
// defer_demo.go 文件
package function_demo
import "fmt"
func DeferDemo() {
num := 100
num += 200
// 延迟调用
// 但是numjavascript的值是该函数调用位置计算的
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 延迟调用内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!
加载中,请稍侯......
精彩评论