SoFunction
Updated on 2025-04-07

Golang's project practice to implement delayed calls

Delayed call

In Go, deferred calls are a very important feature, which allows you to arrange for a function to be executed after the current function is executed, regardless of whether panic occurs or not.

This is usually used for resource cleaning, file closing, unlocking mutex locks, etc.

1. Delayed call

deferThe statement will defer a function until it contains thedeferThe function of the statement is executed when it is about to return. The parameters of the function that is delayed execution will be evaluated immediately, but the function itself will be delayed until the peripheral function returns.

1.1 Use scenarios

  • Resource Cleanup: Such as closing files, network connection, etc.
  • Unlock mutex: After accessing shared resources, make sure the mutex is released.
  • Print debugging information: Print some debug information or log at the end of the function.

1.2 Example

func DeferDemo() {
	num := 100
	num += 200
	// Delayed call	// But the value of num is calculated by the function call position	defer printMessage(num)
	num += 5
	(num)
}

func printMessage(num int) {
	("printMessage func")
	("i am in defer: ", num)
}

Test Method

func TestDeferDemo(t *) {
	DeferDemo()
}

Output result

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

2. panic

panicIt is a built-in function. When an error that cannot be recovered during the program is run, it can be called.panicfunction.

It will immediately interrupt the execution of the current function and start executing the registered delayed call layer by layer (deferstatement).

After the delayed call is executed, the program crashes and prints out and passes topanicThe value of the function.

2.1 Use scenarios

panicIt is usually used to deal with severe runtime errors, such as array out of bounds, null pointer references, etc.

2.2 Example

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)
	("Not executed")
}

Test Method

func Test_panicDemo(t *) {
	panicDemo()
}

Output result

=== 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]:
.func1.2({0x1042b9dc0, 0x1042e3860})
……

3. recover

recoveris a built-in function that is used topanicRecovery in the middle.

recoverIt is only useful when called in a delayed call function.

Called in normal execution processrecoverWill returnnil, and there will be no effect.

If it is called in a delayed call functionrecover, and the function it is located in is due topanicAnd exiting, thenrecoverWill be captured and passed topanicvalue and prevents the program from crashing. At this time, the program will continue to executepanicCode after click (if any).

3.1 Use scenarios

recoverUsually used in the event of potentialpanicAdditional error handling logic is added around the code block to allow the program to elegantly recover in the event of a serious error.

3.2 Example

func recoverDemo() {
	divideFunc := func(a, b int) int {
		if b == 0 {
			panic("divide by zero")
		}
		return a / b
	}

	saveDivideFunc := func() (int, error) {
		defer func() {
			// Capture any possible panic			if r := recover(); r != nil {
				("Recovered from panic:", r)
			}
		}()

		// Try to perform an operation that may trigger panic		result := divideFunc(10, 0)

		// If no panic occurs, the result will be returned		return result, nil
	}

	divideRes, err := saveDivideFunc()
	if err != nil {
		(err)
	} else {
		(divideRes)
	}
}

Test Method

func Test_recoverDemo(t *) {
	recoverDemo()
}

Output result

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

Source code

// defer_demo.go filepackage function_demo

import "fmt"

func DeferDemo() {
	num := 100
	num += 200
	// Delayed call	// But the value of num is calculated by the function call position	defer printMessage(num)
	num += 5
	(num)
}

func printMessage(num int) {
	("printMessage func")
	("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)
	("Not executed")

}

func recoverDemo() {
	divideFunc := func(a, b int) int {
		if b == 0 {
			panic("divide by zero")
		}
		return a / b
	}

	saveDivideFunc := func() (int, error) {
		defer func() {
			// Capture any possible panic			if r := recover(); r != nil {
				("Recovered from panic:", r)
			}
		}()

		// Try to perform an operation that may trigger panic		result := divideFunc(10, 0)

		// If no panic occurs, the result will be returned		return result, nil
	}

	divideRes, err := saveDivideFunc()
	if err != nil {
		(err)
	} else {
		(divideRes)
	}
}
package function_demo

import "testing"

func TestDeferDemo(t *) {
	DeferDemo()
}

func Test_panicDemo(t *) {
	panicDemo()
}

func Test_recoverDemo(t *) {
	recoverDemo()
}

This is the end of this article about Golang's project practice to implement delayed calls. For more related Golang's delayed calls, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!