上面的章节把Go语言的基础知识学的差不多了,这次再学习一个重要的知识点——函数
简介
函数通俗的讲是组织好的、可重复使用的,用于执行指定任务的代码块。
定义
Go语言中函数定义使用func
关键字,语法格式如下:
func 函数名(参数)(返回值){
函数体
}
说明:
函数名
- 由字母、数字、下划线组成,但第一个字母不能是数字,而且同一个包内,函数名也不能重复。参数
- 由参数变量及变量类型组成,多个参数之间使用,
分隔。返回值
- 由返回值变量和变量类型组成,也可以只有返回值类型,多个返回值是必须用()
包裹,并用,
分隔。函数体
- 实现函数具体功能的代码块。
来个小示例吧,求两数之和:
func intSum(x int, y int) int {
return x + y
}
参数
常规写法
参数常规的写法,就像上面的小示例一样,每个参数都有变量名、变量类型组成。
类型简写
如果参数中相邻变量的类型一样,则可以省略类型,比如上面的小示例可以简化为:
func intSum(x, y int) int {
return x + y
}
注:即把变量x
的类型int
给省略了
可变参数
可变参数指的是函数的参数数量不是固定的,此时可以通过在参数的后面加...
来标识,示例如下:
func intSum(x ...int) int {
sum := 0
for _, val := range x {
sum += val
}
return sum
}
func main() {
fmt.Println(intSum(1, 2)) // 3
fmt.Println(intSum(1, 2, 3)) // 6
}
说明:
- 可变参数的变量是一个切片类型
- 可变参数与固定的参数搭配使用时,可变参数要放在固定参数的最后
返回值
Go语言中的返回值和其它语言一样,使用的return
关键字,形式分为以下几种。
单返回值
单返回值顾名思义,即指有一个返回值,比如上面的几个例子,就只有一个返回值。
多返回值
多返回值顾名思义,即指有多个返回值,此时返回值必须用()
包裹起来,示例如下:
func calc(x, y int) (int, int) {
sum := x + y
sub := x - y
return sum, sub
}
返回值命名
返回值命名是指在返回值中把变量名定义好,这样子在函数体里就可以直接使用了(PS:调用方也不用为取返回值变量名发愁了),最后通过return
关键字返回,示例如下:
func calc(x, y int) (sum, sub int) {
sum := x + y
sub := x - y
return
}
调用
上面说了这么多,还有没有说怎么调用呢,其实调用也比较简单,分为两种,接下来我们介绍一下。
函数名调用
直接通过函数名()
的方式调用,这也是开发中最常用的方式,示例如下:
func main() {
fmt.Println(calc(4, 3)) // 7 1
}
函数类型变量调用
即把函数赋值给一个变量,这种不常用,咱也介绍一下吧,来个小示例:
func main() {
aa := calc // 将函数赋值给变量aa
fmt.Printf("type of aa : %T\n", aa) // type of aa : func(int, int) (int, int)
fmt.Println(aa(4, 5)) // 9 -1
}
进阶
高阶函数
函数做为参数
函数可以做为另一个函数的参数,示例如下:
func intSum(x ...int) int {
sum := 0
for _, val := range x {
sum += val
}
return sum
}
func add(x, y int, op func(...int) int) int {
return op(x, y)
}
func main() {
fmt.Println(add(10, 20, intSum)) // 30
}
函数做为返回值
函数也可以做为另一个函数的返回值,示例如下:
func intSum(x ...int) int {
sum := 0
for _, val := range x {
sum += val
}
return sum
}
func do() func(...int) int {
return intSum // 返回一个函数
}
func main() {
cc := do() // 将返回的函数赋值给一个变量
fmt.Println(cc(1, 2, 3)) // 6
}
匿名函数
匿名函数即没有函数名的函数,语法格式如下:
func (参数) (返回值) {
函数体
}
因为匿名函数是没有函数名的,因此就不能通过调用函数名的方式执行,执行它有两个方式:
赋值给变量后执行
即先将匿名函数赋值给一个变量,也相当于给它个名字,然后再执行,如下:
func main() {
aa := func(x, y int) {
fmt.Println(x + y)
}
aa(2, 3) // 5
}
定义好后直接执行
即匿名函数定义好之后,就直接在后面加()
传参即可直接执行,如下:
func main() {
func(x, y int) {
fmt.Println(x + y)
}(4, 5) // 9
}
注:匿名函数在开发中一般用于回调函数和闭包中。
闭包
闭包指的是一个函数与其它相关引用环境组合而成的一个实体。简单来说就是闭包=函数+引用环境
,示例如下:
func main() {
jpgFunc := makeSuffixFunc(".jpg")
fmt.Println(jpgFunc("test")) // test.jpg
}
func makeSuffixFunc(suffix string) func(string) string {
return func(name string) string {
if !strings.HasSuffix(name, suffix) {
return name + suffix
}
return name
}
}
defer语句
Go语言中的defer
语句会将后面跟随的语句进行延迟处理。当defer
所在的函数返回时,延迟处理的语句会逆序执行,也就是先定义的最后执行,最后定义的最先执行。来个小示例感受一下吧~
func main() {
fmt.Println("start")
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
fmt.Println("end")
}
输出:
start
end
3
2
1
再来个经典案例:
func f1() int {
x := 5
defer func() {
x++
}()
return x
}
func f2() (x int) {
defer func() {
x++
}()
return 5
}
func f3() (y int) {
x := 5
defer func() {
x++
}()
return x
}
func f4() (x int) {
defer func(x int) {
x++
}(x)
return 5
}
func main() {
fmt.Println(f1()) // 5
fmt.Println(f2()) // 6
fmt.Println(f3()) // 5
fmt.Println(f4()) // 5
}
再来一个面试题:
func calc(index string, a, b int) int {
ret := a + b
fmt.Println(index, a, b, ret)
return ret
}
func main() {
x := 1
y := 2
defer calc("AA", x, calc("A", x, y))
x = 10
defer calc("BB", x, calc("B", x, y))
y = 20
}
输出:
A 1 2 3
B 10 2 12
BB 10 12 22
AA 1 3 4
内建函数
Go语言中还有一些常用的内建函数,之前的文章中也用到过一些,今天小小总结一下。
内建函数 | 使用说明 |
---|---|
close | 关闭channel 管道 |
len | 求长度,比如:string、array、slice、map、channel |
new | 用来分配内存,主要用来分配值类型的,比如:int、string、struct等,返回的是指针类型 |
make | 用来分配内在,主要用来分配引用类型,比如:map、slice、chan,返回的是它本身 |
panic/recover | 用来做错误的处理 |
函数相关的大概就这些东西了,886