文章15 | 阅读 7615 | 点赞0
函数是基本的代码块,它的作用是可以将实现某个功能的多行代码封装到一段代码块中(即函数),在需要的时候去调用。同个函数可以被多次调用,实现代码重用。
函数一般会有参数和返回值(也可以没有),函数名称、函数参数、函数返回值以及它们的类型被统称为函数签名
在Go语言中,函数有以下一些特点:
Go函数定义格式如下:
func function_name ([parameter list]) [return_type]{
函数体
}
func
开始声明定义函数parameter list
:参数列表,一般格式为 param1 type1, param2 type2...
return_type
:返回值类型,这里可以只写返回值类型,也可以为返回值命名(即支持命名返回值参数的写法:ret1 type1
)Go函数被调用的时候,传入的参数会被复制然后传递到函数内部使用,即函数体中使用的是参数副本。这种方式也称之为值传递
&
符号)作为输入参数传递给函数(即引用传递)。此时传递的是地址的副本,但地址副本指向位置还是原来变量的位置,因此可以通过该指针来修改原来的变量。如果传递的是slice
、map
这类引用类型,它们默认都是采用引用传递return
多个返回值func main(){
r1, r2 := A(1, "A")
}
func A(a int, b string) (int, string) {
c := a + 1
d := b + "aa"
return c, d
}
func main(){
r3 := B(1, 2, 3)
}
func B(a, b, c int) int {
return a + b + c
}
return
后面也可以不写上返回值的名称,默认会返回函数声明中那几个命名的返回值func main(){
r4, r5, r6 := C()
}
func C() (a, b, c int) {
a, b, c = 1, 2, 3
return
}
...type
这样的形式来表示不定长变参,注意不定长变参只能作为最后一个参数。函数会接收一个某个指定类型的类似slice
的参数func main(){
r7 ;= D(0,1,2,3)
}
func D(base int , s ...int) int {
for _, v := range s {
base += v
}
}
这里小朋友是否有个问号:这种方式和你直接把参数放到一个slice
中,再直接传递这个slice
的方式有何区别?区别在于不定长变参是对原来的参数进行拷贝再放到slice中,因此函数内改变它们并不会改变原来的值,而直接传递slice
是引用传递,传递的是slice的指针,函数内改变会改变原来的值
func main(){
p := 1
G(&p)
fmt.Println(p)
}
func G(p *int) {
*p = 2
fmt.Println(*p)
}
func main(){
s := []int{1, 2, 3, 4}
F(s)
fmt.Println(s)
}
func F(s []int) {
s[0] = 5
s[1] = 6
s[2] = 7
s[3] = 8
fmt.Println(s)
}
func main(){
h := H
h()
}
func H() {
fmt.Println("H")
}
func main(){
r := f1(f2(5))
}
func f1(a,b,c int) int {
return a+b+c
}
func f2(a int) (b,c,d int){
b = a
c = a + 1
d = a - 1
return
}
type cb func(int) int
func main() {
testCallBack(1, callBack)
testCallBack(2, func(x int) int {
fmt.Printf("我是回调,x:%d\n", x)
return x
})
}
func testCallBack(x int, f cb) {
f(x)
}
func callBack(x int) int {
fmt.Printf("我是回调,x:%d\n", x)
return x
}
匿名函数,顾名思义即没有名字的函数。匿名函数不能独立地定义,它需要赋值给某个变量,即保存函数的地址到变量中,然后通过变量对函数进行调用。或者定义的同时直接调用
func main(){
i := func(){
fmt.Println("匿名函数赋值给变量再调用")
}
i()
func(){
fmt.Println("匿名函数直接调用")
}()
}
Go的匿名函数支持闭包。关于闭包的概念:
闭包函数:声明在一个函数中的函数,叫做闭包函数
闭包:闭包函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回之后
有关闭包更加深入的理解后面会考虑再写一篇文章来介绍。下面是一段展示闭包的代码,closure
函数中的匿名函数(闭包函数)可以访问到外部函数中的变量x
。程序输出的结果为11
和12
func main(){
f := closure(10)
fmt.Println(f(1))
fmt.Println(f(2))
}
func closure(x int) func(int) int {
return func(y int) int {
return x + y
}
}
defer
函数的作用类似于其它语言中的析构函数,它会在函数体执行结束后再执行,如果有多个defer
函数,它们按照调用顺序的相反顺序逐个执行
defer
函数允许将某些语句推迟到函数返回之前才执行defer
函数一般常用于释放某些已分配的资源,文件关闭,解锁,计时等操作defer
函数的使用:直接在函数前加上defer
关键字即可func main(){
for i := 0; i < 3; i++ {
defer fmt.Println(i) //将逆序输出 2 1 0
}
}
defer
经常可以用在异常恢复的代码块中,在Go中没有Java的try-catch
机制,它是使用panic-recover
模式来处理程序中发生的错误
panic
可以在任意地方引发,但recover
只有在defer
调用的函数中才有效recover
的defer
函数需要定义在发生panic
之前func main(){
beforePanic()
panicRecover()
afterPanic()
}
func beforePanic() {
fmt.Println("before panic")
}
//panic-recover
func panicRecover() {
defer func() {
if err := recover(); err != nil {
fmt.Println("Recover in this")
}
}()
panic("Panic !!!")
}
func afterPanic() {
fmt.Println("after panic")
}
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/xah100147/article/details/106375850
内容来源于网络,如有侵权,请联系作者删除!