首页 > 技术分享 > Golang
收藏

Go语言函数、return、init、匿名、闭包、defer等详解

10/22 14:07
大潇博客 原创文章,转载请标明出处

函数的基本概念

为完成某一功能的程序指令集合,称为函数,Golang中函数分为:系统函数、自定义函数


Golang函数基本语法

func 函数名(形参列表) (返回值类型列表) {

执行语句...

return 返回值1, 返回值2(可选)...

}

说明:

形参列表:表示函数的输入

函数中的语句:表示为了实现某一功能代码块

函数可以有返回值,也可以没有


函数调用过程

说明:

1、在调用一个函数时,会给该函数分配一个独立的新空间,编译器会把这个新空间和栈区的其它空间区分开

2、每个函数对应的栈中,数据空间是独立的,不会混淆

3、当一个函数执行完毕,程序会销毁这个函数对应的栈空间


函数参数传递方式

1、值类型:基本数据类型int系列、float系列、bool、string、数据、结构体struct

2、引用类型:指针、slice切片、map、管道chan、interface接口等


return语句

1、Go函数支持返回(return)多个值(这一点其它编程语言没有)

func 函数名(形参列表) (返回值类型1, 返回值类型2, 返回值类型3...) {

语句...

return 返回值1, 返回值2, 返回值3...

}

2、如果函数 return 返回多个值,接收时使用 _ 符号,就表示占位并忽略某个返回值

有一种极端的写法,可以忽略所有返回值,这种写法没实际意义,仅做说明

3、如果返回值只有一个 ,返回类型列表可以不加括号()


函数使用注意事项和细节讨论

1、函数的形参列表可以是多个,返回值列表也可以是多个

形参列表和返回值列表的数据类型,可以是值类型,也可以是引用类型


2、函数的命名遵循标识符命名规范,首字母不能数字,首字母小写该函数只能被本包文件使用(private),首字母可以被本包文件和其他包文件共同使用

3、函数中的变量是局部的,函数外不生效


4、各数据类型传值与修改的问题

⑴. 基本数据类型 和 数组 默认都是值传递,即进行值拷贝,在函数内修改,不会影响到原来的值

⑵. slice 和 map 是引用传递,在函数内修改,原来的值也会被修改


5、如果希望函数内的变量能修改函数外的变量(指值传递的数据类型),可以传入变量的地址,在函数内以指针的方式操作(效果类似引用)


6、Golang不支持函数重载


7、在Golang中,函数也是一种数据类型,可以将函数赋值给一个变量,该变量就是函数类型,且通过该变量可以对函数调用


8、既然函数是一种数据类型,所以函数可以做为另一个函数的形参被调用,这是一种高阶函数的特性


9、为了简化数据类型定义,Golang支持自定义数据类型(结构体),基本语法:

type 自定义数据类型名 数据类型 //相当于一个别名

比如:

type myInt int  //这时 myInt 就等价于int来使用了

比如:

type getSum func(int, int) int  //这时就等价于一个函数类型 func(int, int) int


10、Golang支持对函数返回值命名(注意函数内部直接对命名的变量使用等号“=”)

函数返回值的命名,return时可变换顺序,接收的顺序按实际return的顺序

注意:对返回值命名后,就等于声明了变量,若函数内部不再赋值,默认return各类型的零值

对返回值命名后,也能return其它变量,使用时,接收实际return的值


11、函数相同类型的参数,可以合并使用一个类型标识,返回值命名同样可以如此


12、Golang支持可变参数,格式

func 函数名(形参... 类型) { ... }

比如:支持0到多个参数

func myFun(args... int) {

}

支持1到多个参数

func myFun(um int, args... int) {

}

说明:可变参数的位置,必须放在形参的最后一个,可变参数(比如上面的args) 是 slice 切片,可通过 args[index] 访问各个值

举例:


init函数

每个 go 文件都可以包含一个 init 函数,该函数会在 main 函数执行前,被 Golang 运行框架调用,也就是说 init 会在 main 函数前被调用,通常可用来做初始化

案例:

如果一个文件包含全局变量定义、init函数、main函数,执行流程是:全局变量定义 -> init函数 -> main函数

init函数可以用来做一些初始化工作

如果文件自身和引入的文件都有变量定义和 init 函数,执行流程是:

引入文件的变量定义 -> 引入文件的init函数 -> 文件自身的函数定义 -> 文件自身的init函数

相同包里的不同文件,定义全局变量、init函数的执行顺序是:按照文件名首字母顺序,先依次定义全局变量,再执行 init 函数,最后执行 main 包中的定义变量、init函数、main函数


匿名函数

Golang支持匿名函数,匿名函数就是没有名字的函数,如果某个函数只希望使用一次,可以考虑使用匿名函数,匿名函数也可以实现多次调用

匿名函数的使用方式,通过案例说明,比如使用匿名函数求两个数的和

全局匿名函数

如果将匿名函数赋值给一个全局变量,那么这个匿名函数,就是全局匿名函数,可以在整个程序中使用


函数的defer

在函数中,程序员经常需要创建资源,比如数据库资源、文件句柄、锁等,为了在函数执行完毕后,及时释放资源,Go的设计者提供了defer延时机制

具体执行步骤:

1、当 go 执行到一个 defer 时,不会立即执行 defer 关键字后的语句,而是将 defer 后的语句压入到一个栈中(可以理解为 defer 栈),然后继续执行 defer 下面语句

2、当函数执行完毕后,再从 defer 栈中,按照先入后出的原则,依次取出语句并执行

在 defer 将语句放入栈时,也会将相关的值拷贝同时入栈

defer 和 return 的执行顺序:

return 的值计算优先于 defer 执行,defer 执行优先于 return 的返回动作,一句话:defer 语句会在函数 return 返回前执行

defer 的最佳实践案例:关闭文件资源、释放数据库连接等


打赏

上一篇:GO设置代理

下一篇:Go语言包的细节

阅读排行

大家都在搜

博客维护不易,感谢你的肯定
扫码打赏,建议金额1-10元
  • 15601023311