defer
用于资源的释放,在归属的函数即将返回时才会延迟的执行。被defer修饰都会在函数返回时执行。
例如:
func main() {
defer fmt.Printf("aaa")
defer fmt.Println("bbb")
defer fmt.Println("ccc")
}
- 结果却是 ccc bbb aaa
当出现多个defer的时候,他们就会想扔到栈里面一样,后进先出。
当defer出现在函数里面的时候
- 首先我们的函数里面的return语言,并不是原子性质的,分成了两个部分
- 第一步:对返回值进行赋值的一个操作
- 第二步:真正执行return语句
- 如果函数里面存在defer的话,那么被defer修饰的语句,会在第一步和第二步之间进行执行
// Go语言中函数的return不是原子操作,在底层是分成两步来执行的
// 第一步: 返回值进行赋值
// 第二步:真的执行ret操作
// 函数中如果存在defer,那么defer执行的时机是在第一步和第二步之间的。
func f1() int {
x := 5
defer func() {
x++
}()
return x
}
func f2() (x int) {
defer func() {
x++
}()
return 5
}
func main() {
fmt.Println(f1())
fmt.Println(f2())
}
- 运行的答案是 5 和 6
- 值得注意的是,当函数里面有参数的时候,修改的是副本,没有参数的时候并且和返回值参数相同的时候,才发生改变。
闭包closure
- 利用匿名函数解决一些需求
例如:
func f1(f func()) {
fmt.Println("this is a f1")
f()
}
func f2(x, y int) {
fmt.Println("this is a f2")
fmt.Println(x + y)
}
// 要求,f1(f2)
- f1函数里面只能是放又给无参的无返回值的函数类型,但是要求运行f1(f2)
- 我们不可能要求同事把f1函数给改了把,所以我们自能改自己的
- 这里我们就可以使用到闭包了
// 要求,f1(f2)
func f3(f2 func(x,y int),x, y int) func() {
tmp := func() {
f2(x,y)
}
return tmp
}
func main() {
f1(f3(f2, 100, 200))
}
- 设置一个f3函数,就可以完美的替代f2,并且还能传送到f1函数里面
- 所以我们可以得到一个结论
闭包 = 函数 + 外部作用域的一个变量
实现原理:
1.函数可以作为返回值
2.函数内部查找变量的顺序,找不到会将外部函数参数也会被读取
再来一个例子,他还可以进行一个后缀名的设置
package main
import (
"fmt"
"strings"
)
// 判断下结尾是以什么结尾的,如果不是就加上去
func makeSuffixFunc(suffix string) func(string) string {
return func(name string) string {
if !strings.HasSuffix(name, suffix) {
return name + suffix
}
return name
}
}
func main() {
jpg := makeSuffixFunc(".jpg")
png := makeSuffixFunc(".png")
fmt.Println(jpg("test"))
fmt.Println(png("test"))
}
- 还是挺不错的
再来一个高级点的,多个函数返回值
func calc(base int) (func(int) int, func(int) int) {
add := func(x int) int {
return base + x
}
sub := func(x int) int {
return base - x
}
return add, sub
}
func main() {
add, sub := calc(100)
fmt.Println(add(5), sub(5))
}
- 看到这么长的返回值不要怕,其实理清楚的就很方便的
- 两个函数,带有参数,还有返回值,对号入座就可以了