defer
是延遲執行的意思。
A defer statement defers the execution of a function until the surrounding function returns.
推遲執行defer的敘述式
,盡可能地拖拖拖等等等,直到目前所在的func打烊結束要回傳時才做事。
這種非得等到最後一刻才去做的精神,和大眾你我一樣很明顯都是拖延病患者,非常的親民。
像我大概就被植入了defer 發文.寫稿(IT鐵人賽)
這樣子的程式。
來看看只有兩行的程式。
func main() {
defer fmt.Println("退出main才執行")
fmt.Println("Hi")
}
/* result:
Hi
退出main才執行
*/
fmt.Println()
var a = 50
func main() {
defer add_a()
fmt.Println(a)
}
func add_a() {
a += 100
}
/* result:
50
*/
https://play.golang.org/p/VRSQqf1_Bly
疑?奇怪,這樣子懶惰到叫人心寒的函式可以用在哪呢?
世上有哪間公司會雇用懶人嗎?
有的話請務必找我過去。
程式會用到defer
主要是需要拖延的時效性
,類似鬧鐘能做到提醒的作用。
在開燈的時候,
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()
一切看似非常地正常、優雅且美好。
兩個defer執行的優先順序,
為了要貫徹拖延的行為,越早分派的任務要越晚達成才行 => 每日拖延(1/1)✔️。
https://play.golang.org/p/IFgv-lt3Y7Z
func main() {
defer print1()
defer print2()
}
func print1() {
fmt.Println("p1")
}
func print2() {
fmt.Println("p2")
}
/* result:
p2
p1
*/
defer
印出的值是多少,更動前的值?還是更動後?
func main() {
assign2(50)
}
func assign2(a int) int {
defer fmt.Println(a) // 任務交代下來的時候 a值是50,然後盡可能地拖延
a = 100 // 老闆更動了a為100
return a
}
/* result:
50
*/
func main() {
assign1(50)
}
func assign1(a int) int {
a = 100 // 老闆更動了a為100
defer fmt.Println(a) // 任務交代下來的時候 a值是100,然後盡可能地拖延
return a
}
/* result:
100
*/
全看上頭交代時的參數
https://play.golang.org/p/MYCoWj7Womg
The deferred call's arguments are evaluated immediately,
but the function call is not executed until the surrounding function returns.
https://play.golang.org/p/2ihaISoyjbd
defer
總想等到店裡打烊時再做行動,
但是如果直接倒店os.Exit
..
func main() {
defer func() {
fmt.Println("我很懶,想等到退出func的時候再印東西")
}()
os.Exit(0) // func直接被砍了
}
/* result:
*/
func main() {
fmt.Println(func1())
}
func func1() int {
var a int
defer func() {
a = 100
}()
return a // defer:『喔 要回傳a了喔,可是func還沒退出所以我不想做事,反正回上司也沒有規定要回傳哪個a,所以擺爛。』
}
/* result:
0
*/
func main() {
fmt.Println(func2())
}
func func2() (a int) {
defer func() {
a = 100
}()
return a //defer:『蛤,要回傳了喔?雖然想擺爛,但上司一開始指名規定要回傳a,先趕一下進度好了。』
}
/* result:
100
*/
https://play.golang.org/p/AE9WS1XOGjo
『自始至終,就是想拖』—— Golang.Defer
請問為什麼 var 在匿名函式中會return 0呀? 有比較明確的原因嗎? 我試著print,a在離開函式之前也確實是100,為什麼最後在main裡面會收到0呢?
我一開始也只是整理結果、不是很理解,
剛剛查了下,發現跟 Naked return
(Named return)有關
https://stackoverflow.com/questions/37248898/how-does-defer-and-named-return-value-work
預先宣告、return回來的值居然是個坑呢,之後找時間補上
https://play.golang.org/p/puh6ijy-GVZ
謝謝解惑,可以請教一下這個答案用什麼關鍵字找出來的嗎?我其實也有嘗試找答案,但不太會下關鍵字。
一開始從匿名函式找 defer anonymous function
,但發現結果不太一樣。後來從函式回傳值的預先宣告 return declare
找,才曉得這個種用法叫 Named return
,然後再加defer
來查
https://golang.org/doc/effective_go.html#defer
GO Defer這裡提到,
The arguments to the deferred function (which include the receiver if the function is a method) are evaluated when the defer executes, not when the call executes.
再出現Defer時, 就會把當時的value傳入了. 並非等到defer被調用才看變數的值. 所以它倆其實不是同一個位子的變數
當初有看到這一段,但不太能理解意思,
看到N大解釋之後更加明白了,
非常感謝
是的,後來發現defer傳入pointer可能會是一個坑。
Go新手小實驗
Defer傳址
結論:func在呼叫前就會把parameter複製一遍放在一邊,所以如果是傳值(50)進去,會印出50,但如果傳址(&50)進去,則會印出100,因為被複製一遍的是地址
不知理解是否正確?