关于go:Go函数下篇defer和闭包

68次阅读

共计 3037 个字符,预计需要花费 8 分钟才能阅读完成。

defer

  1. 应用 defer 注册的匿名函数(提早调用)还能够给它传参,不过是值拷贝

    package main
    
    import "fmt"
    
    func work() int {
     num := 10
     defer func(i int) {
         i += 20
         println("defer 内的后果:", i)
     }(num)
     return num
    }
    
    func main() {ret := work()
     fmt.Println(ret)
    }
    

    输入:

    defer 内的后果: 30
    10

    解析:在 work 函数内,变量 num 传递给了通过 defer 注册了的匿名函数,在匿名函数内做了加 20,但它的后果并未影响到里面的 num 变量,这就是值拷贝。

  2. 当被动调用 os.Exit 退出程序后,defer 会不会执行?试试再说

    package main
    
    import (
     "fmt"
     "os"
    )
    
    func main() {defer func() {fmt.Println("开释锁...")
     }()
     fmt.Println("hello")
     os.Exit(1)
    }
    

    输入:

    hello

    答案很显著了,竟然不会。

  3. 注册自定义的函数为提早调用,模仿个小栗子:关上文件,解决,解决完后敞开该文件

    package main
    
    import ("fmt")
    
    func closeFile() {println("敞开文件")
    }
    
    func work() bool {defer closeFile()
     fmt.Println("关上文件")
     fmt.Println("正在解决...")
     fmt.Println("解决实现!")
     return true
    }
    
    func main() {status := work()
     fmt.Println(status)
    }

    输入:

     关上文件
    正在解决...
    解决实现!true
    敞开文件 

    所以说,defer 的利用场景能够是开释资源或者敞开连贯、敞开文件、开释锁等等,说白了就是:它就是做收尾工作的家伙。

闭包

  1. 闭包初体验

    闭包的实质其实返回的是一个函数,但这个函数有点非凡,为啥说非凡呢?因为在这个函数外面,还有一个函数,这个函数是匿名函数,且在这个匿名函数外面还能够援用内部变量,当被重复调用时,这里援用的内部变量只会初始化一次。因而:闭包 = 函数 + 函数外面的匿名函数 + 匿名函数援用的内部变量

接下来一步一步进行解剖

方才说到闭包的实质其实返回的是一个函数,之前提到过,匿名函数是能够作为函数的返回值的,看上面代码:

func bibao() func() {}

下面的栗子中,定义了一个函数 Bibao,这个函数没有入参,返回值的类型是函数类型,也就是定义成 func(),所以它要返回一个函数才行呢,当初函数体是空的,别急,一步一步解剖。

方才说到在这个函数外面,还有一个函数,这个函数是匿名函数,且还要返回这个匿名函数,看上面的代码:

func bibao() func() {return func() {fmt.Println("hello")
    }
}

func main() {b := bibao()
    b()}

输入:

hello

在 bibao 函数体里,返回了一个匿名函数,这个匿名函数的性能是输入了字符串“hello”,调用 bibao() 把它赋值给变量 b,此刻,变量 b 就是一个函数(它接管的就是返回的匿名函数),变量 b 既然是函数,那就能够进行调用了 b(),所以执行后,输入的是“hello”。

方才说到且在这个匿名函数外面还能够援用内部变量,当被重复调用时,这里援用的内部变量只会初始化一次,看上面代码:

package main

import "fmt"

func bibao(name string) func() string {
    base := "hello"
    return func() string {
        base = base + " " + name
        return base
    }
}

func main() {b := bibao("ttr")
    fmt.Println(b()) // 第 1 次调用
    fmt.Println(b()) // 第 2 次调用
    fmt.Println(b()) // 第 3 次调用
    fmt.Println(b()) // 第 4 次调用
}

输入:

hello ttr // 第 1 次调用的后果输入
hello ttr ttr // 第 2 次调用的后果输入
hello ttr ttr ttr // 第 3 次调用的后果输入
hello ttr ttr ttr ttr // 第 4 次调用的后果输入 

这次对 bibao 函数做了点小革新,它须要接管一个参数 name。在 bibao 函数中,对于匿名函数外部来说,它的内部变量就是 bibao 函数里的 base 变量。调用函数 bibao 并传入 ”ttr”,在匿名函数中进行了字符串拼接,bibao(“ttr”) 初始化了一次,b() 重复调用了 4 次,在匿名函数中援用的内部变量 base,每次调用时返回的是内部变量 base 的多个正本,因为在每次调用时都会为局部变量分配内存(对于整个程序来说,在函数里的 base 变量是局部变量,而对于在 bibao 函数里的匿名函数来说,base 变量是内部变量。)

还能够再这样革新,成果也是一样的:

package main

import "fmt"

func bibao() func(name string) string {
    base := "hello"
    return func(name string) string {
        base = base + " " + name
        return base
    }
}

func main() {b := bibao()
    fmt.Println(b("ttr"))
    fmt.Println(b("ttr1"))
    fmt.Println(b("ttr2"))
}

输入:

hello ttr
hello ttr ttr1
hello ttr ttr1 ttr2

好了,到此为止,闭包到底在哪呢?上面这块就是闭包,bibao 函数返回了这个闭包:

base := "hello"
return func(name string) string {
    base = base + " " + name
    return base
}

闭包是由函数和与其相干的援用环境组合而成的实体,这里所说的函数就是匿名函数,所说的援用环境就是内部变量 base,他们一起组合成了一个实体并返回,这就是闭包。

忽然想到如果把 base 变量放到匿名函数外面,它还是不是一个闭包?看看成果:

package main

import "fmt"

func bibao() func(name string) string {return func(name string) string {
        base := "hello"
        base = base + "" + a +" " + name
        return base
    }
}

func main() {b := bibao()
    fmt.Println(b("ttr"))
    fmt.Println(b("ttr1"))
    fmt.Println(b("ttr2"))
}

输入:

hello ttr
hello ttr1
hello ttr2
  1. 来一个小栗子

    闭包的益处在于,能够缩小全局变量,在函数调用的过程中隐式的传递共享变量,这更具备封装性,更平安了,使其不能随便拜访到共享变量。

    package main
    
    import ("fmt")
    
    func bankcard(name string) func() (string, float32) {
     amount := 10000.0
     return func() (string, float32) {return name, float32(amount)
     }
    
    }
    
    func main() {b := bankcard("xiaoming")
     fmt.Println(b())
    }

本文装载于(喜爱的盆友关注咱们): https://mp.weixin.qq.com/s/O7…

正文完
 0