函数的作用是将相同功能的代码块独立出来,用户可以重复使用。
函数的定义
在Go语言中,函数使用func
关键字来定义,基本格式如下:
func 函数名(参数, ...)(返回值, ...){
函数体
return 返回值
}
其中:
- 函数名:由字母、数字、下划线组成,不能以数字开头,推荐驼峰式命名方式。在同一个包里函数名不能同名;
- 参数:参数由参数变量和参数类型组成,多个参数以
,
隔开; - 返回值:返回值由返回值变量和返回值类型组成,多个返回值以
,
隔开;
例如:
func sum(x int,y int)(sum int){
return x +y
}
说明:函数的参数和返回值是可选的。
函数的调用
定义好函数之后,我们可以通过函数名()
的方式调用函数。
例如:
package main
import "fmt"
func sum(x int, y int) (sum int) {
return x + y
}
func main() {
// 调用函数
ret := sum(10, 20)
fmt.Println(ret)
}
注意:如果调用的函数有返回值,我们可以像上面例子中接收这个返回值,我们也可以不接收。
函数的其他定义方式
类型简写
如果函数的参数中相邻两个参数的类型相同,我们可以把前面的参数类型省略。如下:
func f1(x, y int) (sum int) {
return x + y
}
如上即为x和y都是int类型。
返回值变量省略
上面介绍返回值包含返回值变量和返回值类型,其中的返回值变量可以省略。如下:
func f1(x, y int) int {
return x + y
}
这两种的区别:如果在函数定义的时候写了返回值变量,我们在函数体中可以直接使用这个变量,而且在return的时候可以不写这个变量,如下:
func f1(x, y int) (sum int) {
sum = x + y
return
}
可变参数
可变参数是指函数的参数不固定,在Go语言中的可变参数通过在参数后面加...
来标识。
如下:
func sum(x int, y ...int) int{
sum := x
for _, v := range y{
sum += v
}
return sum
}
注意:
- 可变参数必须放在参数的最后面;
- 可变参数是一个切片,比如上面定义的y就是一个切片;
函数的进阶
变量的作用域
全局变量
在Go语言中定义在函数外部的变量即为全局变量,该变量在程序的整个生命周期都有效,函数中可以访问到全局变量。
该变量的定义必须有关键字var
。如下:
package main
import "fmt"
// 全局变量
// 定义一个全局变量
var a = 100
func main() {
fmt.Println(a) // 输出:100
}
局部变量
在Go语言中,有两种局部变量:
- 定义在函数内,函数内都可以使用;
- 只在函数内某个代码块中使用,代码块执行完,该变量就失效了;
对于第一种,示例如下:
package main
import "fmt"
// 全局变量
// 定义一个全局变量
var a = 100
// 定义一个函数
func f1() {
b := 200
fmt.Println(b)
}
func main() {
fmt.Println(a) // 输出:100
// 调用函数
f1()
}
对于第二种,示例如下:
package main
import "fmt"
// 全局变量
// 定义一个全局变量
var a = 100
// 定义一个函数
func f2() {
if a := 19; a > 10 {
fmt.Println(a)
} else {
fmt.Println("No BB")
}
}
func main() {
fmt.Println(a) // 输出:100
// 调用函数
f2()
}
注意:如果局部变量与全局变量重名,那么局部变量得优先级高于全局变量。
如下:
package main
import "fmt"
// 全局变量
// 定义一个全局变量
var a = 100
// 定义一个函数
func f1() {
a := 200
fmt.Println(a) // 输出:200
}
func main() {
fmt.Println(a) // 输出:100
// 调用函数
f1()
}
函数类型与变量
函数类型
在Go语言中,可以用type
关键字来定义函数类型。如下:
type myFunc func(int,int) int
上面就定义了一个myFunc
类型,它是一个函数类型,它接收两个int参数并返回一个int类型的返回值。
凡是满足这类条件的函数都是myFunc
类型的函数,比如下面的add
和sub
函数都是myFunc
类型的函数:
func add(x, y int) int {
return x + y
}
func sub(x, y int) int {
return x - y
}
那么就可以把add
和sub
赋值给myFunc
的变量,如下:
package main
import "fmt"
func sum(x, y int) int {
return x + y
}
func sub(x, y int) int {
return x - y
}
func main() {
type myFunc func(int, int) int
var test myFunc
test = sum
fmt.Println(test(1, 2))
}
函数类型的变量
既然可以定义函数类型,那么就可以通过该类型来声明变量,这个变量可以进行赋值操作,这个赋值的变量须满足该类型的条件,如上。
高阶函数
函数作为参数
函数可以作为参数传递到其他函数中,如下:
package main
import "fmt"
func f1(x, y int) int {
return x + y
}
func f2(a, b int, f func(int, int) int) int {
sum := f(a, b)
return sum
}
func main() {
ret := f2(1, 2, f1)
fmt.Println(ret)
}
在f2
的函数中定义了三个参数:a
、b
、f
。其中a,b就是普通的int类型的参数,f是一个函数参数,这个函数需要传入两个int类型的参数并返回一个int类型的返回值。
函数作为返回值
函数不仅可以作为参数,它还能作为返回值。如下:
package main
import "fmt"
func f1(a, b int) int {
return a + b
}
func f2(x, y int) func(int, int) int {
fmt.Println(x + y)
return f1
}
func main() {
ret := f2(1, 2)
ret2 := ret(3, 4)
fmt.Println(ret2)
}
如上,在函数f2
中我们定义了一个返回值,其返回值的类型是函数,所以我们在调用完f2
后,接收其返回值,我们可以再一次对这个返回值做函数调用。
匿名函数
在Go语言中,函数内部不能再像之前那样定义标准的函数了,只能定义匿名函数。所谓的匿名函数就是没有函数名的函数。如下:
func(参数)(返回值){
函数体
}
由于匿名函数没有函数名,所以不能像普通函数那样调用。要运行匿名函数有以下两种方式。
第一种,用一个变量去接收匿名函数,然后通过变量来调用函数。如下:
package main
import "fmt"
func main() {
// 定义一个匿名函数,用变量去接收
f1 := func(x, y int) int {
return x + y
}
// 通过变量去调用执行函数
ret := f1(1, 2)
fmt.Println(ret)
}
第二种,自动执行匿名函数。如下:
package main
import "fmt"
func main() {
// 定义一个匿名函数自动执行
func(x, y int) {
fmt.Println(x + y)
}(1, 2)
}
当然,如果这个匿名函数有返回值,而且要接收这个返回值,我们依然要用一个变量去接收它,如下:
package main
import "fmt"
func main() {
// 定义一个匿名函数自动执行
ret := func(x, y int) int {
return x + y
}(10, 20)
fmt.Println(ret)
}
闭包
闭包,首先是一个函数,它是定义在函数内部的函数,它由于可以读取非它本身的外部变量,就称之为闭包。
由于在Go语言中函数内定义函数只能用匿名函数,所以在Go语言中,闭包就要充分利用匿名函数。
如下:
package main
import "fmt"
func f(x int) func(int) int {
return func(y int) int {
return x + y
}
}
func main() {
f1 := f(1)
ret := f1(2)
fmt.Println(ret)
}
上面例子中,函数f
定义的函数作为返回值,所以在内部用到了匿名函数。f1
变量获取到的就是返回的那个匿名函数,它里面引用了外部函数f
的变量x
,这就形成了闭包。在f1
的生命周期里,变量x
会一直有效。
内部函数
内置函数 | 介绍 |
---|---|
close | 主要用来关闭channel |
len | 用来求长度,比如string、array、slice、map、channel |
new | 用来分配内存,主要用来分配值类型,比如int、struct。返回的是指针 |
make | 用来分配内存,主要用来分配引用类型,比如chan、map、slice |
append | 用来追加元素到数组、slice中 |
panic和recover | 用来做错误处理 |
递归函数
递归函数就是自己调用自己。常用的比如计算斐波拉契,阶乘等等。
例子:假如有n层台阶,一次可以走1个,也可以走2个,请问有几种走法
package main
import "fmt"
func taijie(n uint) uint {
if n == 1 {
return 1
}
if n == 2 {
return 2
}
return taijie(n-1) + taijie(n-2)
}
func main() {
ret := taijie(5)
fmt.Println(ret)
}