zoukankan      html  css  js  c++  java
  • Go学习(14):defer

    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
    ", 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
    ", r)
            wg.Done()
            return
        }
        if r.width < 0 {
            fmt.Printf("rect %v's width should be greater than zero
    ", r)
            wg.Done()
            return
        }
        area := r.length * r.width
        fmt.Printf("rect %v's area %d
    ", 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
    ", r)
            return
        }
        if r.width < 0 {
            fmt.Printf("rect %v's width should be greater than zero
    ", r)
            return
        }
        area := r.length * r.width
        fmt.Printf("rect %v's area %d
    ", 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 
    
  • 相关阅读:
    阿里P8聊并发编程:线程中断和终止
    浅谈Java中的锁:Synchronized、重入锁、读写锁
    史上最全Java面试题!进程,线程相关部分下篇(带全部答案)
    @史上最全Java面试题!关于volatile关键字篇(带全部答案)
    @史上最全Java面试题!进程,线程相关部分上篇(带全部答案)
    一道号称“史上最难”java面试题引发的线程安全思考,掌握了吗?
    stopWatch
    mysql语句及执行计划
    Awr
    文件下载
  • 原文地址:https://www.cnblogs.com/DiZhang/p/12544842.html
Copyright © 2011-2022 走看看