函数在golang中是一等公民,这里将围绕普通函数、匿名函数、闭包,看看他们该怎么用。主要讲下匿名函数和闭包。
普通函数声明(定义)
函数在golang中是一等公函数声明包括函数名、形式参数列表、返回值列表(可省略)以及函数体。
func function_name(Parameter_list)(Return_type){
// function body.....
}
- func:它是Go语言的关键字,用于创建函数。
- function_name:它是函数的名称。
- Parameter_list:包含函数参数的名称和类型。
- Return_type:这是可选的,它包含函数返回的值的类型。如果在函数中使用return_type,则必须在函数中使用return语句。
匿名函数
匿名函数顾名思义,没有函数名称的函数。匿名函数在需要函数时定义函数,能以变量的方式传递。
1:定义并同时调用匿名函数
package main
import "fmt"
func main() {
//匿名函数
func(){
fmt.Println("hello xiaoxu code")
}()
}
2:将匿名函数赋值给变量,用一个变量来代替这个函数,有点类似实例化的形式,然后变量调用函数。
package main
import "fmt"
func main() {
//匿名函数赋值给变量f1
f1 := func(data string) {
fmt.Println("hello" + data)
}
//匿名函数调用
f1("xiaoxucode")
}
// helloxiaoxucode
3:匿名函数用作回调函数
// 自定义函数类型
type Callback func(int, int) int
func callbackName(x, y int, callback Callback) int {
return callback(x, y)
}
func add(x, y int) int {
return x + y
}
//调用函数callbackName时,调用真正的实现函数add
fmt.Println(test(10, 20, add))
什么是闭包(Closure)
闭包想必大家都或多或少只听过,但是我感觉不少人还是不清楚到底什么事闭包。其实闭包是由函数及其相关引用环境组合而成的实体(即:闭包=函数+引用环境)。
“官方”的解释是:所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。那么Go语言中闭包是如何实现的呢?
Go语言中的闭包
Go中的闭包就是包含了自由变量的匿名函数:闭是封闭(函数内部函数),包是包含(该内部函数对外部作用域而非全局作用域的变量的引用)
func adder() func() int {
sum := 0
fmt.Println("this iS xiaoxu code")
//返回一个闭包
return func() int {
//返回累加值
sum++
return sum
}
}
func main() {
//初始值为1
adder1 := adder(1)
//adder1打印累加后的值和地址
fmt.Println(adder1())
fmt.Printf("%p\n", &adder1)
//adder1打印累加后的值和地址
fmt.Println(adder1())
fmt.Printf("%p\n", &adder1)
//初始值为2
adder2 := adder(2)
//adder2 打印累加后的值和地址
fmt.Println(adder2())
fmt.Printf("%p\n", &adder1)
// adder1的输出结果
// 0xc0001ff120
// 2
// 0xc0001ff120
// 3
// adder2的输出结果
// 0xc0001ff130
// 3
}
程序中的匿名函数由于在函数体内部引用了外部的自由变量sum而形成了闭包,闭包每次对变量进行加1的操作都是对变量sum引用的修改。
从输出的值来看可以看出来sum的数值发生了变化,但是对应的内存地址却一直没变,因为这里是同一个adder1()匿名函数。但是adder2()中的闭包的内存地址发生了变化,输出的值也发生了变化,因为他们不是在一个基础上进行改动的,所以会发生变化。
如果sum和匿名函数形成的闭包在同一个函数体内话,每次对sum的修改都会保留,而不会重置,上面的例子是adder()单独一个函数,对变量sum的作用域不同,所以adder2()会重置闭包,输出的sum是基于0开始累加的。