Go學習(14):defer
阿新 • • 發佈:2018-11-28
defer
1.1 延遲是什麼?
即延遲(defer)語句,延遲語句被用於執行一個函式呼叫,在這個函式之前,延遲語句返回。
1.2 延遲函式
你可以在函式中新增多個defer語句。當函式執行到最後時,這些defer語句會按照逆序執行,最後該函式返回。特別是當你在進行一些開啟資源的操作時,遇到錯誤需要提前返回,在返回前你需要關閉相應的資源,不然很容易造成資源洩露等問題
- 如果有很多呼叫defer,那麼defer是採用
後進先出
模式 - 在離開所在的方法時,執行(報錯的時候也會執行)
func ReadWrite() bool {
file. Open("file")
defer file.Close()
if failureX {
return false
} i
f failureY {
return false
}
return true
}
最後才執行file.Close()
示例程式碼:
package main
import "fmt"
func main() {
a := 1
b := 2
defer fmt.Println(b)
fmt.Println(a)
}
執行結果:
1
2
示例程式碼:
package main
import (
"fmt"
)
func finished() {
fmt.Println("Finished finding largest")
}
func largest(nums []int) {
defer finished()
fmt.Println("Started finding largest")
max := nums[0]
for _, v := range nums {
if v > max {
max = v
}
}
fmt.Println("Largest number in", nums, "is", max)
}
func main() {
nums := []int{78, 109, 2, 563, 300}
largest(nums)
}
執行結果:
Started finding largest
Largest number in [78 109 2 563 300] is 563
Finished finding largest
1.3 延遲方法
延遲並不僅僅侷限於函式。延遲一個方法呼叫也是完全合法的。讓我們編寫一個小程式來測試這個。
示例程式碼:
package main
import (
"fmt"
)
type person struct {
firstName string
lastName string
}
func (p person) fullName() {
fmt.Printf("%s %s",p.firstName,p.lastName)
}
func main() {
p := person {
firstName: "John",
lastName: "Smith",
}
defer p.fullName()
fmt.Printf("Welcome ")
}
執行結果:
Welcome John Smith
1.4 延遲引數
延遲函式的引數在執行延遲語句時被執行,而不是在執行實際的函式呼叫時執行。
讓我們通過一個例子來理解這個問題。
示例程式碼:
package main
import (
"fmt"
)
func printA(a int) {
fmt.Println("value of a in deferred function", a)
}
func main() {
a := 5
defer printA(a)
a = 10
fmt.Println("value of a before deferred function call", a)
}
執行結果:
value of a before deferred function call 10
value of a in deferred function 5
1.5 堆疊的推遲
當一個函式有多個延遲呼叫時,它們被新增到一個堆疊中,並在Last In First Out(LIFO)後進先出的順序中執行。
我們將編寫一個小程式,它使用一堆defers列印一個字串。示例程式碼:
package main
import (
"fmt"
)
func main() {
name := "Naveen"
fmt.Printf("Orignal String: %s\n", string(name))
fmt.Printf("Reversed String: ")
for _, v := range []rune(name) {
defer fmt.Printf("%c", v)
}
}
執行結果:
Orignal String: Naveen
Reversed String: neevaN
1.6 延遲的應用
到目前為止,我們所寫的示例程式碼,並沒有實際的應用。現在我們看一下關於延遲的應用。在不考慮程式碼流的情況下,延遲被執行。讓我們以一個使用WaitGroup的程式示例來理解這個問題。我們將首先編寫程式而不使用延遲,然後我們將修改它以使用延遲,並理解延遲是多麼有用。
示例程式碼:
package main
import (
"fmt"
"sync"
)
type rect struct {
length int
width int
}
func (r rect) area(wg *sync.WaitGroup) {
if r.length < 0 {
fmt.Printf("rect %v's length should be greater than zero\n", r)
wg.Done()
return
}
if r.width < 0 {
fmt.Printf("rect %v's width should be greater than zero\n", r)
wg.Done()
return
}
area := r.length * r.width
fmt.Printf("rect %v's area %d\n", r, area)
wg.Done()
}
func main() {
var wg sync.WaitGroup
r1 := rect{-67, 89}
r2 := rect{5, -67}
r3 := rect{8, 9}
rects := []rect{r1, r2, r3}
for _, v := range rects {
wg.Add(1)
go v.area(&wg)
}
wg.Wait()
fmt.Println("All go routines finished executing")
}
修改以上程式碼:
package main
import (
"fmt"
"sync"
)
type rect struct {
length int
width int
}
func (r rect) area(wg *sync.WaitGroup) {
defer wg.Done()
if r.length < 0 {
fmt.Printf("rect %v's length should be greater than zero\n", r)
return
}
if r.width < 0 {
fmt.Printf("rect %v's width should be greater than zero\n", r)
return
}
area := r.length * r.width
fmt.Printf("rect %v's area %d\n", r, area)
}
func main() {
var wg sync.WaitGroup
r1 := rect{-67, 89}
r2 := rect{5, -67}
r3 := rect{8, 9}
rects := []rect{r1, r2, r3}
for _, v := range rects {
wg.Add(1)
go v.area(&wg)
}
wg.Wait()
fmt.Println("All go routines finished executing")
}
程式執行結果:
rect {8 9}'s area 72
rect {-67 89}'s length should be greater than zero
rect {5 -67}'s width should be greater than zero
All go routines finished executing