GO函数
GO函数
1.1 函数分类
在go语言中,函数是第一类对象,我们可以将函数保存到变量中。函数主要有具名和匿名之分,包级函数一般都是具名函数,具名函数是匿名函数的一种特例,当匿名函数引用了外部作用域中的变量时就成了闭包函数,闭包函数是函数式编程语言的核心。
举例代码如下:
-
具名函数:就和C语言中的普通函数意义相同,具有函数名,返回值以及函数参数的函数。
func Add(a,b int) int { return a+b }
-
匿名函数:指不需要定义函数名的一种函数实现方式,它由一个不带函数名的函数声明和函数体组成。
var Add = func(a, b int) int { return a+b }
解释几个名词如下:
1.闭包函数:返回为函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域。
2.一级对象:支持闭包的多数语言都将函数作为第一级对象,就是说函数可以存储到变量中作为参数传递给其他函数,最重要的是能够被函数动态创建和返回。
3.包:go的每一个文件都是属于一个包的,也就是说go是以包的形式来管理文件和项目目录结构的
1.2 函数声明和定义
GO语言函数定义格式如下:
func function_name([parameter list])[return types]{
函数体
}
解析 | |
---|---|
func | 函数由func开始声明 |
function_name | 函数名称 |
parameter list | 参数列表 |
return_types | 返回类型 |
函数体 | 函数定义的代码集合 |
1.3 函数传参
Go语言中的函数可以有多个参数和多个返回值,参数和返回值都是以传值的方式和被调用者交换数据。在语法上,函数还支持可变数量的参数,可变数量的参数必须是最后出现的参数,可变数量的参数其实是一个切片类型的参数。
当可变参数是一个空接口类型时,调用者是否解包可变参数会导致不同的结果,我们解释一下解包的含义,代码如下:
func main(){
var a = []int{1,2,3}
Print(a...) // 解包
Print(a) // 未解包
}
func Print(a ...int{}){
fmt.Println(a...)
}
以上当传入参数为a...
时即是对切片a进行了解包,此时其实相当于直接调用Print(1,2,3)
。当传入参数直接为 a
时等价于直接调用Print([]int{}{1,2,3})
1.4 函数返回值
不仅函数的参数可以有名字,也可以给函数的返回值命名。
举例代码如下:
func Find(m map[int]int,key int)(value int, ok bool){
value,ok = m[key]
return
}
如果返回值命名了,可以通过名字来修改返回值,也可以通过defer语句在return语句之后修改返回值,举例代码如下:
func main(){
for i := 0;i<3;i++{
defer func(){fmt.println(i)}()
}
}
// 该函数最终的输出为:
// 3
// 3
// 3
以上代码中如果没有defer其实返回值就是0,1,2
,但defer语句会在函数return之后才会执行,也就是或只有以上函数在执行结束return之后才会执行defer语句,而该函数return时的i
值将会达到3,所以最终的defer语句执行printlin的输出都是3。
defer语句延迟执行的其实是一个匿名函数,因为这个匿名函数捕获了外部函数的局部变量v,这种函数我们一般叫闭包。闭包对捕获的外部变量并不是传值方式访问,而是以引用的方式访问。
这种方式往往会带来一些问题,修复方法为在每一轮迭代中都为defer函数提供一个独有的变量,修改代码如下:
func main() {
for i := 0; i < 3; i++ {
i := i // 定义一个循环体内局部变量i
defer func(){ println(i) } ()
}
}
func main() {
for i := 0; i < 3; i++ {
// 通过函数传入i
// defer 语句会马上对调用参数求值
// 不再捕获,而是直接传值
defer func(i int){ println(i) } (i)
}
}
1.5 递归调用(递归函数)
Go语言中,函数还可以直接或间接地调用自己,也就是支持递归调用。Go语言函数的递归调用深度逻辑上没有限制,函数调用的栈是不会出现溢出错误的,因为Go语言运行时会根据需要动态地调整函数栈的大小。这部分的知识将会涉及goroutint和动态栈的相关知识。
它的语法和c很相似,格式如下:
func recursion(){
recursion() /* 函数调用自身 */
}
func main() {
recursion()
}