Definition
defer
statement is the keyword of go language. defer
statement would delay the execution of function, method and anonymous method until the innermost call function return. Attention please, the arguments of defer function evaluate instantly while the execution is delay. Example is shown in the below part.
Basic Usage
Using the keyword defer
before a function call, to imply a delayed ‘function’. The ‘function’ means 1. Function call, 2. Method call , 3. Anonymous method call.
Usage Format
1 | defer funcName(arguments) |
Usage With Different Object
1 | // Function |
Here is a example to show the basic usage of defer:
1 | package main |
Usage Scenario
Clean up Resource
In programming, remember clean up all the resources(close file , disconnect tcp etc) is not a easy thing. With defer
keyword the clean up part will always be executed. Here is a close file example, which compare defer
difference with different code style:
without
defer
keyword, close file clause is duplicate:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28package main
import (
"io"
"log"
"os"
)
func main() {
if err := write("readme.txt", "This is a readme file"); err != nil {
log.Fatal("failed to write file:", err)
}
}
func write(fileName string, text string) error {
file, err := os.Create(fileName)
if err != nil {
return err
}
_, err = io.WriteString(file, text)
if err != nil {
file.Close()
return err
}
file.Close()
return nil
}with
defer
keyword, the complier always remember close file;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26package main
import (
"io"
"log"
"os"
)
func main() {
if err := write("readme.txt", "This is a readme file"); err != nil {
log.Fatal("failed to write file:", err)
}
}
func write(fileName string, text string) error {
file, err := os.Create(fileName)
if err != nil {
return err
}
_, err = io.WriteString(file, text)
defer file.Close() // defer keyword
if err != nil {
return err
}
return nil
}Deal With
recover
function
The example above is a complicated and non-idiomatic way to handle runtime problems that would have been better dealt with by just passing
error
values. I understand that there are definitely edge-cases where use ofpanic()
andrecover()
might make sense. That said, I’ve been writing Go professionally for about 5 years now and I’ve never felt a sufficient need, especially in application code. Do your best to refactor your project so you can just returnerror
s like the good designers intended._Lane Wagner
Clean up operation is not necessary with defer
keyword, for a well programmed code could achieve the same effect. While defer
is the necessary part of build-in function recover
.
In go language, the panic
and recover
mechanism is used to stop panic
spread. If a panicking goroutine exit without being recovered, it will cause the whole program crash. In other language, try/catch mechanism has the similar effect. Thanks to the recover
mechanism, the below goroutine did not collapse.
1 | package main |
Feature
Call Sequence of Defer Function
The Sequence of Defer Function is
FILO
.1
2
3Actually the goroutine hold two function call stack;
- For a deferred function call, the invocation moment is the moment when it is pushed into the defer-call stack of its caller goroutine.
- For a goroutine function call, the invocation moment is the moment when the corresponding goroutine is created.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26package main
import "fmt"
// Functions
func mul(a1, a2 int) int {
res := a1 * a2
fmt.Println("Result: ", res)
return 0
}
func main() {
mul(1, 9)
defer mul(6, 9)
defer mul(5, 9)
defer mul(4, 9)
defer mul(3, 9)
defer mul(2, 9)
}
// Result: 9
// Result: 18
// Result: 27
// Result: 36
// Result: 45
// Result: 54Could Modify Named Return Result of Nesting Functions.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16package main
import "fmt"
func Triple(n int) (r int) {
defer func() {
r += n // modify the return value
}()
return n + n // <=> r = n + n; return
}
func main() {
fmt.Println(Triple(5)) // 15
}Evaluation Moment
defer
function call would evaluate the arguments instantly and delayed the execution of function body.
1 | Unlike other higher-order functions in Go, when you “pass” a function to the defer keyword, you pass an entire function call, not just the name of the function. This allows the function’s arguments to be evaluated immediately. The defer keyword just ensures that the body of the function won’t run until the parent function returns. |
1 | package main |