闭包基本介绍:
闭包就是一个函数和与其相关的引用环境组合的一个整体。
package main
import "fmt"
func main() {
//使用AddUpper函数
//当反复调用f函数,因为n是初始化一次,因此每调用一次就进行累计。
//我们要搞清楚闭包的关键,就是要分析出返回的函数引用到了哪些变量,因为函数和它引用的变量共同构成闭包。
f := AddUpper()
result := f(1)//第一次n是10 那么结果就是10+1=11
fmt.Println("result", result)//11
result2 := f(2)//里面的n已经是11了 那么结果是11+2=13
fmt.Println("result2", result2)//13
}
//AddUpper是一个函数返回的数据类型是:func(int) int
func AddUpper() func(int) int {
//闭包的说明:返回的是一个匿名函数,这个匿名函数引用到了函数外的n,因此这个匿名函数就和n就形成一个整体构成了闭包。
//可以这样理解:闭包是一个类,函数是操作,n是字段。函数和它使用到的n构成闭包
var n int = 10
return func(x int) int {
n = n + x
return n
}
}
加深对闭包理解:
package main
import (
"fmt"
"strconv"
)
func main() {
//使用AddUpper函数
f := AddUpper()
result := f(1)
fmt.Println("result", result) // str= hello11 result 11
result2 := f(2) //里面的n已经是11了 那么结果是11+2=13
fmt.Println("result2", result2) //str= hello1113 result2 13
}
func AddUpper() func(int) int {
var n int = 10
var str string = "hello"
return func(x int) int {
n = n + x
str = str + strconv.Itoa(n) //str = hello+n
fmt.Println("str=", str)
return n
}
}
闭包的案例:
package main
import (
"fmt"
"strings"
)
func main() {
a := makeSuffix(".jpg")
result3 := a("mafu")
fmt.Println("result3", result3) //mafu.jpg
result4 := a("haha.jpg")
fmt.Println("result4", result4) //haha.jpg
}
//传入一个后缀,判断这个一个文件名是否包含次后缀,如果包含直接返回该文件名,不包含就加上。
//返回的匿名函数和makeSuffix(suffix string)中的suffix变量组成一个闭包,因为返回的函数引用到了suffix变量。
func makeSuffix(suffix string) func(name string) string {
return func(name string) string {
if !strings.HasSuffix(name, suffix) {
//如果name没有指定的后缀suffix。则加上
return name + suffix
}
//有后缀则直接返回
return name
}
}
闭包的好处:如果使用传统方法,也可以完成这个需求,但是传统的方法需要每一次都传入后缀,比如.jpg。而闭包因为可以保留上次引用的某个值。所以我们传入一次就可以反复使用了。
defer关键字:
为了在函数执行完毕后,及时释放资源。Go中提供defer(延时机制)
package main
import "fmt"
func main() {
//当sum函数执行完毕后再执行defer栈中的代码。
res := sum(1, 2)
fmt.Println("res=", res) //第四 res=3
}
func sum(n1 int, n2 int) int {
//当执行到defer时,会将defer语句压入到独立的栈中(defer栈)
defer fmt.Println("ok1 n1=", n1) //第三 ok1 n1=1
//当执行到defer时,会将defer语句压入到独立的栈中(defer栈) 栈是先进后出 所以这句语句后进先出来
defer fmt.Println("ok2 n2=", n2) //第二 ok2 n2=2
result := n1 + n2
fmt.Println("ok3 result=", result) //第一 result=3
return result
}
细节说明:
-
当go执行到一个defer时,不会立即执行defer后的语句,而是将defer后的语句压入到一个栈中,然后继续执行函数的下一条语句。
-
当函数执行完毕后,在从defer栈中,依次从栈顶取出语句执行(先进后出)
-
在defer将语句放入栈时,也会将相关的值拷贝同时入栈。
func sum(n1 int, n2 int) int {
//当执行到defer时,会将defer语句压入到独立的栈中(defer栈)
defer fmt.Println("ok1 n1=", n1) //第三 ok1 n1=1 后面n1虽然自增+1 但是对栈中的n1没有影响 因为值拷贝
//当执行到defer时,会将defer语句压入到独立的栈中(defer栈) 栈是先进后出 所以这句语句后进先出来
defer fmt.Println("ok2 n2=", n2) //第二 ok2 n2=2
n1++ //2
n2++ //3
result := n1 + n2
fmt.Println("ok3 result=", result) //第一 result=3
return result
}
标签:闭包,defer,int,fmt,result,func,Go
From: https://www.cnblogs.com/mafu-blogs/p/17965026