1.闭包就是一个函数和与其相关的引用环境组合的一个整体
package main
import (
"fmt"
)
// 累加器
func addUpper() func (int) int {
n := 10
return func (x int) int {
n += x
return n
}
}
func main() {
f := addUpper()
fmt.Println(f(1)) // 11
fmt.Println(f(2)) // 13
fmt.Println(f(3)) // 16
}
addUpper是一个函数,返回类型是func(int) int
返回的是一个匿名函数,但是这个匿名函数引用到函数外的n,因此这个匿名函数和n形成一个整体,构成闭包。
当我们反复调用f时,n只初始化一次,每调用一次,就产生累加。
要分析清楚,返回的函数使用哪些变量。
返回的匿名函数和这个匿名函数用到的函数外的变量构成闭包
反复调用这个函数时,它用到的变量只初始化一次。
2.闭包示例
package main
import (
"fmt"
"strings"
)
func makeSuffix(suffix string) func(string) string {
return func(name string) string {
// name 没有指定后缀 加上
// 否则返回原来的名字
if !strings.HasSuffix(name, suffix) {
return name + suffix
}
return name
}
}
func main() {
f := makeSuffix(".jpg")
var s string
fmt.Println("input file name")
fmt.Scanln(&s)
fmt.Println("文件名处理后=", f(s))
}
如果用传统方法,需要反复传入suffix,用闭包的方法传入一次即可。
3.defer
函数中,常常需要创建资源(数据库连接,文件句柄,锁)
为了函数执行完毕后,及时释放资源,go提供defer延时机制
package main
import (
"fmt"
)
func sum(n1 int, n2 int) int {
defer fmt.Println("ok1 n1=", n1)
defer fmt.Println("ok2 n2=", n2)
res := n1 + n2
fmt.Println("ok3 res=", res)
return res
}
func main() {
res := sum(10, 2)
fmt.Println("res=", res)
}
执行到defer时,先不执行,将defer后面的语句压入到独立的栈(defer栈)
函数执行完毕后,再从defer栈,出栈执行
4.在defer将语句放入栈时,也会将相关的值拷贝,同时入栈
package main
import (
"fmt"
)
func sum(n1 int, n2 int) int {
defer fmt.Println("ok1 n1=", n1) // 10
defer fmt.Println("ok2 n2=", n2) // 2
n1++
n2++
res := n1 + n2
fmt.Println("ok3 res=", res) // 14
return res
}
func main() {
res := sum(10, 2)
fmt.Println("res=", res)
}
defer用于及时释放函数创建的资源
5.引用类型:指针、slice、map、管道chan、interface
引用类型默认是引用传递,变量存地址,内存一般在堆上分配
没有变量引用这个地址时,地址对应的数据空间就成为一个垃圾,由GC回收
如果希望函数内能改变函数外的变量,传入变量的地址&
6.函数外声明/定义的变量为 全局变量,作用域在整个包有效
首字母大写,作用域为整个程序
编译器采用就近原则,先用局部变量
Name := “tom”
等价于两句 定义和赋值
赋值不能在函数体外,报错