函数、闭包与指针
函数
语法格式:
func 函数名(参数列表)(返回参数列表){
//函数体
}
- (1) go语言中的函数支持可变参数,此函数的参数数量是不定的
arg …int告诉GO这个函数接收不定数量的参数,这些参数类型全是int,变量arg是一个int的slice
func myfunc(arg ...int){ }
-
(2) GO语言的函数可以返回多个值
-
(3) 返回参数列表可以是数据的数据类型,或者是:变量名+变量类型的组合
func Test() (a int,b uint){}
func Test() (a,b uint){} -
(4) 若只有一个返回值且不声明返回值变量,那么可以省略()
func Test() int{}
函数变量(函数作为值)
- 在GO语言中函数也是一种类型,可以保存在变量中
- 可以通过type来定义一个自定义类型。函数的参数完全相同(包括:参数类型,个数,顺序),函数返回值相同
1. 定义一个函数类型
2. 创建这个类型的函数
3. 作为参数调用
下例: 函数被当成参数传递到另一个函数中
func getString(str string) string {
return str + "666"
}
//第二参数为函数(要标明返回值类型和参数)
func Test02(str string, myfunc func(string) string) string {
return myfunc(str)
}
func main() {
str := "zzx"
fmt.Println(Test02(str, getString))
}
下例:使用type定义一个函数的类型,被传参时函数类型就可以写出自己定义的类型
type getFunc func(string) string
func getString(str string) string {
return str + "666"
}
func Test02(str string, myfunc getFunc) string {
return myfunc(str)
}
func main() {
str := "zzx"
fmt.Println(Test02(str, getString))
}
匿名函数
- 匿名函数没有函数名,只有函数体,函数可以作为一种类型被赋值给变量,匿名函数往往以变量方式被传递
- 匿名函数经常被用于实现回调函数、闭包等
1. 下例中:在定义时调用匿名函数(没有函数名最后的(100)是实参)
func main() {
func(i int) {
fmt.Println(i)
}(100)
}
**2. 下例:**将匿名函数赋值给变量(这个变量是函数类型)
func main() {
f := func(str string) {
fmt.Println(str)
}
f("世界你好!")
}
3. 作为回调函数
type genFunc func(float64) string
func main() {
arr := []float64{
1, 4, 9, 16, 25, 30}
//进行求平方根操作
result := getgenSlice(arr, func(val float64) string {
val = math.Sqrt(val)
return fmt.Sprintf("%.2f", val)
})
fmt.Print(result)
}
//遍历切片,对其中每个值进行运算处理
func getgenSlice(arr []float64, f genFunc) []string {
var result []string
for _, value := range arr {
result = append(result, f(value))
}
return result
}
闭包
- 闭包是由函数和与其相关的引用环境组合而成的实体
- 闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例
一个编程语言需要有一下特性来支持闭包: - 函数可以作为另一个函数的返回值或参数,还可以作为一个变量的值
- 在一个函数内部可以定义另一个函数
- 允许定义匿名函数
- 可以捕获引用环境,并把引用环境和函数代码组成一个可调用的实体
- 闭包函数的返回值一定是一个函数类型的
- 闭包函数可以不写函数名,闭包函数里面要有匿名函数
下例使用闭包实现计数器: (adder函数内的sum不清零,main函数中变量res是一直存在的adder中的sum也是一直存在的,所以没有被当做垃圾回收)
示例1:
func main() {
res := adder()
fmt.