Go语言函数的基本用法!
package main
import (
"fmt"
)
/*
函数function
-Go函数不支持嵌套、重载、默认参数
-但支持以下特性:
无序声明原型,不定长度变参,多返回值,命名返回值参数
匿名函数,闭包
-定义函数使用关键字func,且左大括号不能另起一行
-函数也可以作为一种类型使用
*/
func A(a int, b string, c int) int {
//代表参数有三个,返回值是一个int型
return 1
}
func B(a, b, c int) {
//参数也可以这样写
}
func C() (a, b, c int) {
a = 1
b = 1
c = 1 //代表返回值a,b,c,注意在此处abc已经是局部变量
return //在这里可以省略abc,因为abc是唯一的,它是局部变量
}
func D(b string, a ...int) { //不定长变参的使用,注意不定长变参只能作为参数列表最后一个参数
fmt.Println(a)
}
func E(s ...int) {
s[0] = 3
s[1] = 4
//可见传入的是一个slice类型
fmt.Println(s)
} //不定长变参传入的是个slice,但是是个拷贝,这个和直接传入slice不同
func F(s []int) {
//不是传入了指针,是拷贝的是地址,所以可以改变主函数中的那个slice
s[0] = 3
s[1] = 4
fmt.Println(s)
}
func G() {
fmt.Println("this is G!")
}
func H(x int) func(int) int {
return func(y int) int {
return x + y
}
} //这个函数参数是int x,而返回值是函数!
func main() {
D("s", 2, 3, 4) //输出结果[2 3 4],可见"s"被b读取,2,3,4被a读取。
fmt.Println("------")
a, b := 1, 2
E(a, b) //输出[3,4]
fmt.Println(a, b) //输出1,2
//由此可见,实际上传入E的是一个slice的拷贝,并不是slice本身
fmt.Println("------")
s := []int{1, 2}
F(s) //输出[3 4]
fmt.Println(s) //输出[3 4]
fmt.Println("------")
c := G
c() //输出this is G!
//可见,函数也可以作为类型,在Go语言中,一切皆类型啊!
fmt.Println("------")
d := func() {
fmt.Println("我是匿名函数!")
}
d()
fmt.Println("------")
//这个例子创建了匿名函数!
e := H(10)
fmt.Println(e(1))
fmt.Println(e(2))
//闭包(虽然我不懂)
}
defer
-的执行方式类似其他语言中的析构函数,在函数体执行结束后按照调用顺序的相反顺序逐个执行
-即使函数发生严重错误也会执行
-支持匿名函数的调用
-常用于清理资源、文件关闭、解锁以及记录时间等操作
-通过与匿名函数配合可在return之后修改函数计算结果
-如果函数体内某个变量作为defer时匿名函数的参数,则在定义defer时即已经获得了拷贝,否则则是引用某个变量的地址
-Go没有异常机制,但是有panic/recover模式来处理错误
-Panic可以在任何地方引发,但recover只有在defer调用的函数中有效
defer的普通调用
package main
import "fmt"
func main() {
fmt.Println("a")
defer fmt.Println("b")
defer fmt.Println("c")
fmt.Println("-----")
}
/*运行结果
[ `go run temp.go` | done: 874.0399ms ]
a
-----
c
b
*/ //在函数体执行结束后按照调用顺序的相反顺序逐个执行
package main
import "fmt"
func main() {
for i := 0; i < 3; i++ {
defer fmt.Println(i)
}
}
/*运行结果
[ `go run temp.go` | done: 652.4791ms ]
2
1
0
*/
闭包下的defer
package main
import "fmt"
func main() {
for i := 0; i < 3; i++ {
defer func() {
fmt.Println(i)
}() //最后这对括号的作用是调用这个函数,如A()是调用A函数,Sum()是调用Sum函数
}
}
/*运行结果如下
[ `go run temp.go` | done: 705.7846ms ]
3
3
3
*/ //这里的i是用的引用类型,在退出循环之后,i已经是3了。而上一个例子是每循环一次defer一个fmt.Println(i),相当于复制进去了。
//这是闭包使用的时候的特殊情况
defer配合recover()使用
注意:panic(“Panic!”)发生后,recover()函数可以检测到,并且返回一个指针,我们用一个变量来接受,并且判断这个指针是否为nil,如果为nil就说明没有引发panic,否则引发了panic,还有recover()必须在defer的函数内部使用。
package main
import "fmt"
func main() {
A()
B()
C()
}
func A() {
fmt.Println("Func A")
}
func B() {
defer func() {
if err := recover(); err != nil {
fmt.Println("Recover in B")
}
}()
panic("Panic in B")
}
func C() {
fmt.Println("Func C")
}
/*运行结果如下:
[ `go run temp.go` | done: 727.6154ms ]
Func A
Recover in B
Func C
*/
slice 和 map 都是引用类型的拷贝
匿名函数不能作为顶级函数,最外层函数不能是匿名函数
defer-panic-recover体制
panic用于处理如数组越界等无法恢复的错误
recover函数可以从panic状态恢复过来
注意defer的执行顺序
有疑问加站长微信联系(非本文作者)