Hi,大家好,我是明哥。
在自己學習 Golang 的這段時間裏,我寫了詳細的學習筆記放在我的個人微信公衆號 《Go編程時光》,對於 Go 語言,我也算是個初學者,因此寫的東西應該會比較適合剛接觸的同學,如果你也是剛學習 Go 語言,不防關注一下,一起學習,一起成長。
我的在線博客:http://golang.iswbm.com 我的 Github:github.com/iswbm/GolangCodingTime
Go裏的流程控制方法還是挺豐富,整理了下有如下這麼多種:
- if - else 條件語句
- switch - case 選擇語句
- for - range 循環語句
- goto 無條件跳轉語句
- defer 延遲執行
今天是最後一篇講控制流程了,內容是 defer 延遲語句,這個在其他編程語言裏好像沒有見到。應該是屬於 Go 語言裏的獨有的關鍵字,但即使如此,閱讀後這篇文章後,你可以發現 defer 在其他編程語言裏的影子。
1. 延遲調用
defer 的用法很簡單,只要在後面跟一個函數的調用,就能實現將這個 xxx
函數的調用延遲到當前函數執行完後再執行。
defer xxx()
這是一個很簡單的例子,可以很快幫助你理解 defer 的使用效果。
import "fmt"
func myfunc() {
fmt.Println("B")
}
func main() {
defer myfunc()
fmt.Println("A")
}
輸出如下
A
B
當然了,對於上面這個例子可以簡寫爲成如下,輸出結果是一致的
import "fmt"
func main() {
defer fmt.Println("B")
fmt.Println("A")
}
2. 即時求值的變量快照
使用 defer 只是延時調用函數,此時傳遞給函數裏的變量,不應該受到後續程序的影響。
比如這邊的例子
import "fmt"
func main() {
name := "go"
defer fmt.Println(name) // 輸出: go
name = "python"
fmt.Println(name) // 輸出: python
}
輸出如下,可見給 name 重新賦值爲 python
,後續調用 defer 的時候,仍然使用未重新賦值的變量值,就好在 defer 這裏,給所有的這是做了一個快照一樣。
python
go
3. 多個defer 反序調用
當我們在一個函數裏使用了 多個defer,那麼這些defer 的執行函數是如何的呢?
做個試驗就知道了
import "fmt"
func main() {
name := "go"
defer fmt.Println(name) // 輸出: go
name = "python"
defer fmt.Println(name) // 輸出: python
name = "java"
fmt.Println(name)
}
輸出如下,可見 多個defer 是反序調用的,有點類似棧一樣,後進先出。
java
python
go
3. defer 與 return 孰先孰後
至此,defer 還算是挺好理解的。在一般的使用上,是沒有問題了。
在這裏提一個稍微複雜一點的問題,defer 和 return 到底是哪個先調用?
使用下面這段代碼,可以很容易的觀察出來
import "fmt"
var name string = "go"
func myfunc() string {
defer func() {
name = "python"
}()
fmt.Printf("myfunc 函數裏的name:%s\n", name)
return name
}
func main() {
myname := myfunc()
fmt.Printf("main 函數裏的name: %s\n", name)
fmt.Println("main 函數裏的myname: ", myname)
}
輸出如下
myfunc 函數裏的name:go
main 函數裏的name: python
main 函數裏的myname: go
來一起理解一下這段代碼,第一行很直觀,name 此時還是全局變量,值還是go
第二行也不難理解,在 defer 裏改變了這個全局變量,此時name的值已經變成了 python
重點在第三行,爲什麼輸出的是 go ?
解釋只有一個,那就是 defer 是return 後才調用的。所以在執行 defer 前,myname 已經被賦值成 go 了。
4. 爲什麼要有 defer?
看完上面的例子後,不知道你是否和我一樣,對這個defer的使用效果感到熟悉?貌似在 Python 也見過類似的用法。
雖然 Python 中沒有 defer ,但是它有 with 上下文管理器。我們知道在 Python 中可以使用 defer 實現對資源的管理。最常用的例子就是文件的打開關閉。
你可能會有疑問,這也沒什麼意義呀,我把這個放在 defer 執行的函數放在 return 那裏執行不就好了。
固然可以,但是當一個函數裏有多個 return 時,你得多調用好多次這個函數,代碼就臃腫起來了。
若是沒有 defer,你可以寫出這樣的代碼
func f() {
r := getResource() //0,獲取資源
......
if ... {
r.release() //1,釋放資源
return
}
......
if ... {
r.release() //2,釋放資源
return
}
......
if ... {
r.release() //3,釋放資源
return
}
......
r.release() //4,釋放資源
return
}
使用了 defer 後,代碼就顯得簡單直接,不管你在何處 return,都會執行 defer 後的函數。
func f() {
r := getResource() //0,獲取資源
defer r.release() //1,釋放資源
......
if ... {
...
return
}
......
if ... {
...
return
}
......
if ... {
...
return
}
......
return
}
系列導讀
24. 超詳細解讀 Go Modules 前世今生及入門使用