Go interview question topic (1): Talk about the Golang defer keyword you understand

The defer keyword is a feature of the Go language that is often used in our work, and it is also a knowledge point favored by interviewers. Today, through this article, I will help you master it thoroughly.

Click here to download the interview question document for free

From beginner to proficient in go language , click here to download for free.

deferTwo major features

defer is a keyword in golang. It mainly has two major characteristics:

- Delayed call: Call execution after the current function execution is completed.

func f1(){
    
    
	defer fmt.Println("hello world")

	fmt.Println("hello defer!")
}

Output result:

$ go run main.go
hello defer!
hello world

Last in first out: When there are multiple defer functions, the execution order is last in first out.

func f2(){
    
    
	defer fmt.Println("hello 1!")
	defer fmt.Println("hello 2!")
	defer fmt.Println("hello 3!")

	fmt.Println("hello defer!")
}

Output results

$ go run main.go
hello defer!
hello 3!
hello 2!
hello 1!

Execution order of defer and return

The execution order of defer and return is a point that is often examined during interviews and needs to be well understood by Taoists.

First, let’s take an example and look at the output of the code in the following situation.

func f1() (r int){
    
    
	defer func(){
    
    
		r++
	}()
	return 0
}

func f2() (r int) {
    
    
	t:=5
	defer func() {
    
    
		t = t+5
	}()
	return t
}

func f3() (r int) {
    
    
	defer func(r int) {
    
    
		r = r+5
	}(r)
	return 0
}

func main(){
    
    
	fmt.Println(f1())
	fmt.Println(f2())
	fmt.Println(f3())
}

It is recommended that friends think about the answer first and then look at it later.

$ go run main.go
1
5
0

Fellow Daoist Zhang San thought to himself: Damn, are you kidding? Isn’t it 0, 10, 5...

Okay, let’s analyze them one by one:

Here we need to first understand the execution order of the return statement.

The return statement itself is not an atomic instruction. It will first assign a value to the return value and then return, as follows

func f4() (r int) {
    
    
	return 1
}

//执行过程:
r:=1 //赋值
ret //执行返回

When a defer expression is included, the function return process is as follows:

First assign a value to the return value, then call the defer expression, and finally return the result

That is, for f1()

func f1() (r int){
    
    
	defer func(){
    
    
		r++
	}()
	return 0
}

//执行过程:
r:=0 //赋值
r++  //defer
ret  //r=1

For f2

func f2() (r int) {
    
    
	t:=5
	defer func() {
    
    
		t = t+5
	}()
	return t
}

//执行过程
t:=5
r:=t
t=t+5 //defer
ret  //r=5

For f3(), the parameter r passed during defer is actually a value copy.

Therefore, the modification of r in defer will not affect the return value result. It helps to understand that if r is replaced by t, the result is the same, that is, it is equivalent to

func f3() (r int) {
    
    
	defer func(t int) {
    
    
		t = t+5
	}(r)
	return 0
}

//执行过程
r:=0
t = r, t = t +5 //defer
ret // r=0

Application scenarios of defer

Scenario 1: Resource release

When we use resources in code, such as opening a file, it is easy for the resource to not be closed due to forgetting to release it or due to logical errors. Using defer at this time can avoid this resource leak. Let’s take a look at the following code first:

file,_ := os.Open("test.txt")
//process为业务逻辑处理
if err:=process(file);err!=nil {
    
    
  return
}
file.Close()

There is a serious problem in the above code. If err!=nil is returned directly, the file.close() statement to close the resource will not be executed, resulting in resource leakage.
And after writing a series of business logic processing, it is easy for us to forget to close resources, resulting in resource leakage. Therefore, one principle should be kept in mind: add defer to automatically clean up after each successful resource application. No matter how many returns the function has, the resources will be released correctly.
The correct writing logic is as follows:

file,_ := os.Open("test.txt")
defer file.Close()
//process为业务逻辑处理
if err:=process(file);err!=nil {
    
    
  return
}

Scenario 2: Exception capture

For exception handling in programs in Golang, there is no try catch, but there are panic and recover. When a panic is thrown in the program, if it is not recovered in time, the service will hang up directly, causing serious consequences, so we generally use recover to catch exceptions.

func main(){
    
    
	defer func(){
    
    
		if ok:=recover();ok!=nil{
    
    
			fmt.Println("recover")
		}
  }()
	panic("error")
}

The above two scenarios are what we must be familiar with. Of course, we can also use the features of defer to elegantly implement things like code tracing, recording function parameters and return values, etc.

# Scenario 3: Code tracking

We test whether this function is executed by tracking the information that the program enters or leaves a function.

func main(){
    
    
	f1()
	f2()
}

func f1(){
    
    
	defer trace_leave(trace_enter("f1()"))
	fmt.Println("f1()程序逻辑")
}

func f2(){
    
    
	defer trace_leave(trace_enter("f2()"))
	fmt.Println("f2()程序逻辑")
}

func trace_enter(msg string) string{
    
    
	fmt.Println("enter: ",msg)
	return msg
}

func trace_leave(msg string) {
    
    
	fmt.Println("leave: ",msg)
}

The output is as follows:

$go run main.go
enter:  f1()
f1()程序逻辑
leave:  f1()
enter:  f2()
f2()程序逻辑
leave:  f2()

Scenario 4: Print the parameters and return value of the function

The execution result of a certain function is not as expected. We can use defer to print the parameters and return value of the function in one step instead of printing debugging statements in multiple places.

func main(){
    
    
	func1("hello")
}

func func1(str string) ( res string) {
    
    
	defer func() {
    
    
		fmt.Printf("func1(%s) = %s", str, res)
	}()
	res = fmt.Sprintf("%s, jack!",str)
	return
}

Output result:

$go run main.go
func1(hello) = hello, jack!

Summary of interview points

  • Two major characteristics of defer
  • Execution order of defer and return
  • Application scenarios of defer

postscript

If you have any questions about the interview techniques mentioned in this article, you can reply in the comment area. Let’s learn together and make progress together!

Follow the public account [Jiandao Programming], there is a back-end technical interview point every day

Guess you like

Origin blog.csdn.net/m0_73728511/article/details/132767575