golang语言学习#7-函数function

Go语言中函数不支持嵌套,重载和默认参数,但是支持以下特性:

  • 无需声明原型
  • 不定长度变参
  • 多返回值
  • 命名返回值参数
  • 匿名函数
  • 闭包

定义函数时使用关键字func,且左大括号不能另起一行,同时,函数也可以作为一种类型使用

接下来我们来创建几个函数

	func A(){
		fmt.Println("A")
	}
	func B(a int, b string)(int, string){
		
	}
	func C(a int, b int)(int int){
		
	}
	func D(a, b int)(a, b int){
		
	}
	func E()(int, int, int){
		a, b, c := 1, 2, 3
		return a, b, c
	}
	func F()(a, b, c int){
		a, b, c = 1, 2, 3
		return //return a, b, c
	}
        func G()(a ...int){   //不定场变参需要放在所有参数的末尾
        }

匿名函数

	func main(){
		a := func(){
		    fmt.Println("main a")
		}
		a()
	}

闭包

	func main(){
		c := closure("111")
		fmt.Println(c("222"))
		fmt.Println(c("333"))
	}
	func closure(a string) func(string) string {
		return func(b string) string {
			return a + b
		}
	}

我们来对闭包拆解一下,其实闭包相当于在方法的参数返回值位置声明一个方法类型的返回值,即func closure()(返回func类型){},在return中返回 func类型,而返回值中的func类型继续定义了一个函数 func()(){}来返回string类型,由此,可以得到closure(a string)传入参数"111",得出结果"111222","111333".

对于闭包来说,闭包中绑定的是外层函数中的变量本身,不是变量当时的值

defer

defer的一些特性

defer的执行方式类似其他语言中的析构函数,在函数体执行结束后,按照调用顺序的相反顺序逐个执行
即使函数发生严重错误也会执行
支持匿名函数的调用
常用语资源清理,文件关闭,解锁以及记录时间等操作
通过与匿名函数配合可在return之后修改函数计算结果
如果函数体内某个变量作为defer时匿名函数的参数,则在定义defer时即已经获得了拷贝,否则则是引用某个变量的地址
Go没有异常机制,但有panic/recover模式来处理错误

panic可以在任何地方引发,但recover只有在defer调用函数中有效

	func main(){
		fmt.Println("a")
		defer fmt.Println("b")
		defer fmt.Println("c")
		
		for i := 0; i < 3; i++ {
			defer func(){
				fmt.Println(i)
			}()
		}
	}

通过前面的defer特性,我们来预测一下这段代码的输出情况,首先输出a,因为defer都在函数体执行结束后执行,与栈的输出方式一样,是后进先出,所以,再次输出的是for语句里的defer,那defer的值为什么呢,由于程序执行结束后,i的值已经变为3,且程序执行3次,所以输出3次3,之后继续输出c,b

输出结果:

a
3
3
3
c
b

异常panic 和 恢复recover

Go中可以抛出一个panic的一场,然后在defer中通过recover来捕获这个一场,然后正常恢复程序运行

代码片段1:

	func main(){
		A()
		B()
		C()
	}
	
	func A(){
		fmt.Println("Func A")
	}
	
	func B(){
		panic("Panic in B")
		defer func(){
			if err := recover(); err != nil{
				fmt.Println("Recover in B")
			}
		}()
	}

	func C(){
		fmt.Println("Func C")
	}
代码片段2:
	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")
	}
输出结果1:
Func A
panic: Panic in B

goroutine 1 [running]:
main.B()
	D:/eclipse-workspace/Demo/src/main/demo.go:129 +0x40
main.main()
	D:/eclipse-workspace/Demo/src/main/demo.go:120 +0x2c

输出结果2:

Func A
Recover in B
Func C

观察两段代码片段,代码1中defer在panic之后,代码2中defer在panic之前执行,我们知道当运行到panic时,代码会抛出异常的同时会终止程序,后续的defer并不运行,所以我们能看到输出结果1中输出了panic in B后,不在继续输出了,但是当defer在panic之前时,通过对defer的特性了解,在发生严重错误时,defer依旧执行,所以,我们能看到执行了defer之中的recover去恢复了程序,从而获得了Func c

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值