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)
fmt.Println("main end")
}
Started finding largest
Largest number in [78 109 2 563 300] is 563
Finished finding largest
main end
finished() function will be called just before the largest function returns.
Deferred methods
Defer is not restricted only to functions. It is perfectly legal to defer a method call too.
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
Arguments evaluation
package main
import (
"fmt"
)
func printA(a int) {
fmt.Println("value of a in deferred function", a) //2. 5
}
func main() {
a := 5
defer printA(a)
a = 10
fmt.Println("value of a before deferred function call", a) //1. 10
}
Stack of defers
When a function has multiple defer calls, they are pushed on to a stack and executed in Last In First Out (LIFO) order.
package main
import (
"fmt"
)
func main() {
name := "Naveen"
fmt.Printf("Original String: %s\n", string(name)) //Naveen
fmt.Printf("Reversed String: ") //neevaN
for _, v := range name {
defer fmt.Printf("%c", v)
}
}
Practical use of defer
the code of without defer.
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")
}
我们可以注意到wg.Done()的执行都是在return的前一步。所以可以优化
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")
}