匿名函数:
匿名函数类似于函数声明,但是没有函数名
func (函数参数列表) (函数返回值列表){
函数内部代码
}
在函数声明后可以加入参数直接调用
func main() { g := func(a int) uint { //匿名函数 return uint(a + 14) }(10) //声明后调用 f := func(a int) uint { //匿名函数 return uint(a + 14) } re := f(100) fmt.Println(g, re) }
运行结果
24 114
闭包:
闭包是由函数及其相关引用环境组合而成的实体(即:闭包=函数+引用环境)
简单的看就是匿名函数作为返回值
拿个网上的例子:
参考:https://www.cnblogs.com/ralap7/p/9195677.html
func squares() func() int { var x int return func() int { x++ return x * x } } func main() { f1 := squares() f2 := squares() fmt.Println("first call f1:", f1()) fmt.Println("second call f1:", f1()) fmt.Println("first call f2:", f2()) fmt.Println("second call f2:", f2()) }
运行结果:
first call f1: 1
second call f1: 4
first call f2: 1
second call f2: 4
在这里函数就是squares,引用环境就是squares内部,虽然f1,f2都是x的平方,但是他们的环境不同所以两次运行结果都是相同的。
一开始用着C的思维一直想不懂闭包,函数里的变量不是分配到栈中用完就释放了吗,到后面学到了变量逃逸机制后才开始理解因为Go会自动分析语句识别出作用域,因为外部有对x的引用,所以变量x逃逸到了堆中保存而不是在栈中,所以这种写法是可以的。
go build --gcflags=-m main.go
命令可以看到变量逃逸到堆上而不是栈上,所以变量被保存在函数环境中。
函数可变参数:
参数类型:...interface{}
func test1 (a ...interface{}) func test2 (a int, b ...interface{})//可变参数需要放在不可变参数后
当不可变参数和可变参数同时出现在函数参数中时,可变参数需要放在不可变参数后
通过类型断言和range取出可以取出值
func printTypeValue(slist ...interface{}) string { for _, s := range slist { // 将interface{}类型格式化为字符串 str := fmt.Sprintf("%v", s) // 类型的字符串描述 var typeString string // 对s进行类型断言 switch s.(type) { case bool: // 当s为布尔类型时 typeString = "bool" case string: // 当s为字符串类型时 typeString = "string" case int: // 当s为整型类型时 typeString = "int" } } return typeString }