函数
定义
func 函数名(传参类型) 返回值类型{}
func main() {
r := sum(1,2);
fmt.Println(r) // 3
test(); // aaa
m,n := text();
fmt.Println(m,n) //1 aa
}
// 返回数值类型
func sum(x int,y int) int{
return x + y;
}
// 没有返回值
func test(){
fmt.Println("aaa")
}
// 返回值可以命名变量,相当于在函数内声明了变量。
func sum(x int,y int) (res int){
res = x + y;
return // 返回值命名过的话可以直接return
}
// 多个返回值
func text() (int,string){
return 1,"aa"
}
// 当参数连续多个类型一致时,可以简写参数类型
func text1(x,y,z int,a,s,d string) {
...
}
// 可变长参数
// 可变长参数必须放在函数参数的最后
func main() {
f1("aaa",1,2,3,4,5) // aaa [1 2 3 4 5]
}
func f1(x string,y ...int){
fmt.Println(x)
fmt.Println(y) // y 的类型为切片
}
defer
定义
defer
的语句将会在函数将要执行return
时在进行操作
正常情况下
func main() {
test(); // 1 2 3
}
func test(){
fmt.Println(1);
fmt.Println(2);
fmt.Println(3);
}
使用defer
后
func main() {
test(); // 1 3 2
}
func test(){
fmt.Println(1);
defer fmt.Println(2);
fmt.Println(3);
}
defer
的使用场景通常在关闭链接的时候使用,比如链接数据库,读取文件等等。
当多个defer
同时出现时,遵循先进后出原则。
func main() {
test(); // 1 5 4 3 2
}
func test(){
fmt.Println(1);
defer fmt.Println(2);
defer fmt.Println(3);
defer fmt.Println(4);
fmt.Println(5);
}
defer
运行时机
在Go
语言的函数中return
语句在底层并不是原子操作,它分为给返回值赋值和RET
指令两步。而defer
语句执行的时机就在返回值赋值之后,RET
指令之前。
小案例:
func main() {
fmt.Println(test()); // 5
}
func test() int{
x := 5;
defer func(){
x++
}();
return x;
}
匿名函数和闭包
匿名函数一般用在函数内部,是个没有名字的函数
x1 := func (x, y int){
fmt.Println(x + y);
}
x1(1,2); // 3
看到这或许会有疑问,这样写的话为什么不直接定义一个带名字的函数?
这是因为函数内是不可以定义有名字的函数,同时匿名函数若是只调用一次的话,可以定义为立即执行函数。(你没看错,和js
的语法一致)
func (){
fmt.Println(1111)
}();
闭包的作用是在于使让内部函数使用外部变量。
func main() {
a := test(1);
a(); // 2
a(); // 3
}
func test(x int) func() {
return func (){
x++;
fmt.Println(x);
};
}
内置函数
目前Go
语言中没有异常机制,但是使用panic
/ recover
模式来处理错误。panic
可以在任何场景下引发,但recover
只有在defer
调用的函数中有效。举个例子:
func main() {
a();
b();
c();
}
func a(){
fmt.Println("1");
}
func b(){
panic("报错啦")
}
func c(){
fmt.Println("3");
}
输出:
在程序运行期间,b
函数运行出错,抛出错误并退出程序执行。这个时候可以使用recover
来恢复现场并且获取报错信息。
func main() {
a();
b();
c();
}
func a(){
fmt.Println("1");
}
func b(){
defer func(){
err := recover();
fmt.Println("释放数据库连接。。。")
fmt.Println(err)
}();
panic("报错啦")
}
func c(){
fmt.Println("3");
}
输出:
可以看到程序不会因为报错而停止运行,而是继续执行c
函数。
注意事项:
recover
必须搭配defer
使用defer
一定要在可能引发panic
语句之前定义,否则将会永远运行不到。