iT邦幫忙

2021 iThome 鐵人賽

DAY 13
0

defer

A defer statement defers the execution of a function until the surrounding function returns.
推遲執行defer的敘述式,盡可能地拖拖拖等等等,直到目前所在的func打烊結束要回傳時才做事。

defer是延遲執行的意思,主要用於宣告function結束前的動作

延遲執行的意思如下

package main

import (
	"fmt"
)

var a = 50

func main() {
	defer add_a()
	fmt.Println(a)
}

func add_a() {
	a += 100
}

執行後結果如下

50

你可以發現我們是先執行Println才執行add_a()

程式會用到defer主要是需要拖延的時效性,類似鬧鐘能做到提醒的作用。

Close File throuth defer

常用的場合如下:

像是把使用在讀檔後的關檔,這樣也不會忘記。

f, err := os.Open("test.txt")
if err != nil {
    return err
}
defer f.Close()

也常運用在關閉channel關閉DB之中。

db, err := sql.Open("mysql", "USER:PASSWORD@/DB")
	if err != nil {
		log.Fatalln(err)
	}
	defer db.Close()

Executing order of defer

兩個defer執行的優先順序,為了要貫徹拖延的行為,越早分派的任務要越晚達成才行。

defer的執行順序

package main

import (
	"fmt"
)

func main() {
	defer print1()
	defer print2()
}

func print1() {
	fmt.Println("p1")
}

func print2() {
	fmt.Println("p2")
}

執行後可得以下結果

p2
p1

修改defer中的參數

package main

import (
	"fmt"
)

func main() {
	assign2(50)
}

func assign2(a int) int {
	defer fmt.Println(a) 
	a = 100              
	return a
}

執行後可得以下結果

50
package main

import (
	"fmt"
)

func main() {
	assign1(50)
}

func assign1(a int) int {
	a = 100
	defer fmt.Println(a)
	return a
}

執行後可得以下結果

100

defer with os.Exit()

package main

import (
	"fmt"
	"os"
)

func main() {
	defer func() {
		fmt.Println("output")
	}()
	os.Exit(0)
}

執行後可得以下結果


由於程式先執行了os.Exit(0),導致後面的defer不會被執行。

Anonymous Function with defer

package main

import (
	"fmt"
)

func main() {
	fmt.Println(func1())
}

func func1() int {
	var a int
	defer func() {
		a = 100
	}()
	return a
}

執行後可得以下結果

0
func main() {
	fmt.Println(func2())
}

func func2() (a int) {
	a = 50
	defer func() {
		a = 100
	}()
	return a 
}

執行後可得以下結果

100

看得出上述兩個範例的差異了麻?

差別在於一個func1不指定要回傳哪個int變數,但func2指定要回傳a變數!

也因此,func1在直接return的時候,由於並未指定要a,因此defer就讓return先執行。

func2指定要a變數了,因此defer發現它必須要執行完賦予a值的任務才能讓他return

Summary

defer是個很簡單的觀念,但裡頭卻包含著許許多多較不直觀的地雷,也因此特意開一章節來替大家釐清排雷! 希望以後不會誤踩地雷。


上一篇
Day12 Select
下一篇
Day14 Gin and Go Mod
系列文
fmt.Println("從零開始的Golang生活")30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言