文章目录
- 普通函数声明
- 带变量名的返回值
- 函数变量
- 匿名函数
- 定义时调用
- 将匿名函数赋值给函数变量
- 作为回调函数
- 可变参数函数
- defer语句
- 方法
Go支持普通函数、匿名函数和闭包
&ems;Go中的函数是一等公民,可以像其他类型一样使用,赋值、传递参数、接收方法等
普通函数声明
func 函数名(参数列表) (返回参数列表){
函数体
}
一个包内,函数名称不能重名
func foo(a, b string) (string, bool) {
return a + b, true
}
同一类型参数可以简写,返回值可以有多个
带变量名的返回值
声明函数时可以给返回值变量名,在函数体内可以作为变量使用,return语句后不用写要返回的内容
func foo(a, b string) (c string) {
c = a + b
return
}
如果返回值带变量名,必须所有返回值都有变量名,混用无法通过编译
函数变量
Go中,函数也是一种类型,可以赋值和传递
func foo(a, b string) (c string) {
c = a + b
return
}
func main() {
var f func(string, string) string
f = foo
f2 := foo
fmt.Println(f, f2)
}
函数变量的类型要写明函数的参数类型和返回参数类型,或者用简短变量,打印结果是2个相同地址,猜测是函数入口地址
匿名函数
匿名函数类似Java中的匿名类,不同的是匿名类是匿名实现接口,Go中是直接匿名定义函数
Go中定义匿名函数,缺省函数名,其他与普通函数相同,一般有以下用法
定义时调用
func(参数表)返回类型{
函数体
}(调用执行参数)
func(s string) {
fmt.Println(s)
}("hello world")
tmp := func(a, b int) int {
return a + b
}(2, 3)
fmt.Println(tmp)
//hello world
//5
将匿名函数赋值给函数变量
tmp := func(a, b int) int {
return a + b
}
作为回调函数
func foo(a []int, f func(int) int) int {
var sum int
for _, v := range a {
sum += f(v)
}
return sum
}
func main() {
num := []int{1, 2, 3, 4, 5}
ans := foo(num, func(i int) int {
return i * i
})
fmt.Println(ans)
}
可以回调不同的函数对切片值做不同的操作后求和
可变参数函数
func foo(x ...int) {
fmt.Println(reflect.TypeOf(x))
}
在函数参数表中,类型前加...
即表示该参数接受可变参数,在函数体内会自动组装为一个切片使用
调用时,既可以传入多个参数,也可以传入切片后加...
,不能这样传数组
foo(1, 2, 3, 4, 5)
var a = []int{1, 2, 3, 4, 5}
foo(a...)
打印地址可以发现传的是切片的引用值,也就是数据所在的实际地址
interface{}
代表任意类型,如果函数定义为
func foo(x ...interface{}){......}
就可以传入任意数量任意类型的参数
defer语句
defer
语句后的内容,会在函数结束前调用,函数可以是正常结束,也可以是宕机时
func main() {
defer fmt.Println("11111")
defer fmt.Println("22222")
defer fmt.Println("33333")
fmt.Println("hello world")
}
执行结果为
hello world
33333
22222
11111
多个defer
语句,调用顺序是先定义后调用,这也符合申请释放资源的顺序,即后申请的资源需要先释放
依靠defer
语句的特点,可以完成其他语言中finally块的内容,即释放资源的工作,如关闭文件、关闭Socket等
方法
Go中没有类的概念,自然也不会在类中定义函数作为类的方法使用
Go中定义方法
type MyInt int
func (x *MyInt) Increase() {
*x++
}
函数名前是一个接收器,代表了可以调用该方法的对象类型,同时会通过传值进入方法,所以想要修改自身,需要传递指针进来
接收器可以是任意的定义在当前包中的自定义类型,即用type声明的类型
用接收器对象调用执行
var v MyInt
v = 5
v.Increase()
fmt.Println(v) //6