Go interview question: talk about the defer keyword you understand

Hello, I'm brother Xiao Dao.

The defer keyword is a go language feature often used in our work, and it is also a knowledge point favored by the interviewer. Today, I will take you to master it thoroughly through this article.

Two features of defer

defer is a keyword in golang. It has two main features:

  • Delayed invocation: execution is executed after the execution of the current function is completed.
func f1(){
    defer fmt.Println("hello world")

    fmt.Println("hello defer!")
}

Output results:

$ 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 investigated during the interview, which needs to be well understood by Taoist friends.

First, let's take a chestnut and see the output of the code in the following cases.

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())
}

I suggest friends think about the answer first and then look back.

$ go run main.go
1
5
0

Three friends of Zhang thought: lying in the trough, are you kidding? Isn't it 0, 10, 5

OK, let's analyze it one by one:

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

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

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

//Execution process:
r:=1 //assignment
ret //Execute return

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

First assign 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
}

//Execution process:
r:=0 //assignment
r++  //defer
ret  //r=1

For f2

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

//Execution process
t:=5
r:=t
t=t+5 //defer
ret  //r=5

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

Therefore, the modification of r in defer will not affect the return value result, which is helpful to understand that if r is replaced by t, the result is equivalent, that is, equivalent to

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

//Execution process
r:=0
t = r, t = t +5 //defer
ret // r=0

Application scenario of defer

Scenario 1: resource release

When we use resources in code, such as opening a file, it is easy to forget to release or cause the resources not to be closed due to logical errors. At this time, using defer can avoid this kind of resource leakage. Let's look at the following code first:

file,_ := os.Open("test.txt")
//process is business logic processing
if err:=process(file);err!=nil {
  return
}
file.Close()

The above code has a serious problem, such as err= After nil return s directly, the resource closing statement of file.close() will not be executed, resulting in resource leakage.

After a series of business logic processing and writing, it is also easy to forget to close resources, resulting in resource leakage. Therefore, we should keep in mind a principle: add defer automatic cleanup after each successful resource application. No matter how many return s 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 is business logic processing
if err:=process(file);err!=nil {
  return
}

Scenario 2: exception capture

In Golang, there is no try catch for exception handling in programs, 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, resulting in serious consequences. Therefore, we generally use recover to catch exceptions.

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

We must be familiar with the above two scenarios. Of course, we can also use the defer feature to gracefully implement some functions such as code tracking and recording function parameters and return values.

Scenario 3: Code Tracking

We test whether a 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()Program logic")
}

func f2(){
    defer trace_leave(trace_enter("f2()"))
    fmt.Println("f2()Program logic")
}

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

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

The output results are as follows:

$go run main.go
enter:  f1()
f1()Program logic
leave:  f1()
enter:  f2()
f2()Program logic
leave:  f2()

Scenario 4: print function parameters and return values

The execution result of a function does not meet expectations. We can use defer to print the parameters and return values of the function in one step, rather than 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 results:

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

Summary of interview points

  • Two features of defer
  • Execution order of defer and return
  • Application scenario of defer

Post language

If you have any questions about the interview technical points mentioned in this article, you can reply in the comment area. Ha, let's learn and make progress together!

Pay attention to the official account [simple programming], a back-end technology interview point every day.

This article is composed of blog one article multi posting platform OpenWrite release!

Keywords: Go

Added by scottchr226 on Sat, 04 Dec 2021 04:56:15 +0200