reference source

Control Flow

Defer

Do it until it is time to return.

func main() {
	fmt.Println("start")
	defer fmt.Println("middle")
	fmt.Println("end")
}

start
end
middle

defer is LIFO, just like stack

func main() {
	defer fmt.Println("start")
	defer fmt.Println("middle")
	defer fmt.Println("end")
}

end
middle
start

Because defer is not executed until the end of the function, if it is used in the loop, it may cause a large amount of memory to be unable to be released until the end of the function, not the end of the loop.

func main() {
	for i := 0; i < 2; i++ {
		defer fmt.Println("defer", i)
		fmt.Println("normal", i)
	}
	fmt.Println("AA")
}

normal 0
normal 1
AA
defer 1
defer 0

If you want to use defer functions in the loop, such as releasing resources after fetch api, you can put them in a new function.

func main() {
	for i := 0; i < 2; i++ {
		test(i)
	}
	fmt.Println("AA")
}
func test(i int) {
	defer fmt.Println("defer", i)
	fmt.Println("normal", i)
}

normal 0
defer 0
normal 1
defer 1
AA

The variables in defer are taken at the moment, not before return

func main() {
		a := 1
		defer fmt.Println(a)
		a = 2
}

1

Panic (exception)

Panic is not necessarily a fatal error, as long as the application knows how to deal with panic, otherwise the program will be stopped.

func main() {
	fmt.Println("start")
	panic("nono")
	fmt.Println("end")
}

start
panic: nono

Interaction between panic and defer

defer will be executed before return, and panic will cause the application to end, so defer will be executed before panic.

func main() {
	fmt.Println("start")
	defer fmt.Println("deffered")
	panic("nono")
	fmt.Println("end")
}

start
deffered
panic: nono

Recover

Before reading recover, you must first know how to write anonymous functions

callback & anonymous function

func(){...}() is an anonymous function, the front is written as func (like callback), and the back () means to be executed

func main() {
	test(func() { fmt.Println(123) })
}
func test(a func()) {
	a()
}

123

Now use recover() inside the anonymous function

Because defer will be executed before panic, it means that Exception has already occurred. If there is no exception, recover will return nil.

func main() {
	fmt.Println("start")
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("Error:", err)
		}
	}()
	panic("nono")
	fmt.Println("end")
}

start
Error: nono

stack function

As long as the panic has a recover to catch it, the higher-level function will not interrupt the execution due to the panic, but the function of the panic itself will be interrupted.

func main() {
	fmt.Println("start")
	test()
	fmt.Println("end")
}
func test() {
	fmt.Println("start test")
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("Error:", err)
		}
	}()
	panic("nono")
	fmt.Println("end test")
}

start
start test
Error: nono
end

Throw new exception in recover

If the error cannot be handled with recover(), you can use panic() again and throw the exception to the upper function.

func main() {
	fmt.Println("start")
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("Error from test:", err)
		}
	}()
	test()
	fmt.Println("end")
}
func test() {
	fmt.Println("start test")
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("Error:", err)
			panic(err)
		}
	}()
	panic("nono")
	fmt.Println("end test")
}

start
start test
Error: nono
Error from test: nono