概述
函数是组织好的、可重复使用的执行特定任务的代码块。它可以提高应用程序的模块性和代码的重复利用率。Go 语言从设计上对函数进行了优化和改进,让函数使用起来更加方便。因为Go语言的函数本身可以作为值进行传递,既支持匿名函数和闭包,又能满足接口,所以 Go 语言的函数属于一等公民。
函数的定义
Go语言中定义函数使用func
关键字,具体格式如下:
func 函数名(参数)(返回值){
函数体
}
- 由字母、数字、下划线组成。但函数名的第一个字母不能是数字。在同一个包内,函数名也称不能重名(包的概念详见后文)。
- 参数:参数由参数变量和参数变量的类型组成,多个参数之间使用
,
分隔。 - 返回值:返回值由返回值变量和其变量类型组成,也可以只写返回值的类型,多个返回值必须用
()
包裹,并用,
分隔。 - 函数体:实现指定功能的代码块。
用函数定义一个求两个数之和的函数:
func sum(x int, y int) int {
return x + y
}
func main() {
s := sum(1,2)
fmt.Println(s)
}
运行结果:
3
参数
类型简写
函数的参数中如果相邻变量的类型相同,可以省略类型,如下:
func Sum(x, y int) int {
return x + y
}
上面的代码中,Sum
函数有两个参数,这两个参数的类型均为int
,因此可以省略x
的类型,因为y
后面有类型说明,x
参数也是该类型。
可变参数是指函数的参数数量不固定。Go语言中的可变参数通过在参数名后加...
来标识。
注意:可变参数通常要作为函数的最后一个参数。
可变参数
可变参数就是指函数的参数数量不固定。Go语言中的可变参数通过在参数名 后加...
来标识。
注意:可变参数通常要作为函数的最后一个参数。
package main
import "fmt"
func intSum2(x ...int) int {
fmt.Println(x) //x是一个切片
sum := 0
for _, v := range x {
sum = sum + v
}
return sum
}
func main() {
ret1 := intSum2()
ret2 := intSum2(10)
ret3 := intSum2(10, 20)
ret4 := intSum2(10, 20, 30)
fmt.Println(ret1, ret2, ret3, ret4) //0 10 30 60
}
运行结果:
[]
[10]
[10 20]
[10 20 30]
0 10 30 60
返回值
Go语言中通过return
关键字向外输出返回值。
多返回值
Go语言中函数支持多返回值,函数如果有多个返回值时必须用()
将所有返回值包裹起来。
func add(a, b int) (c int) {
c = a + b
return
}
func calc(a, b int) (sum int, avg int) {
sum = a + b
avg = (a + b) / 2
return
}
func main() {
var a, b int = 1, 2
c := add(a, b)
sum, avg := calc(a, b)
fmt.Println(a, b, c, sum, avg)
}
运行结果:
1 2 3 3 1
返回值命名
函数定义时可以给返回值命名,并在函数体中直接使用这些变量,最后通过return
关键字返回。
package main
import "fmt"
func calc(x, y int) (sum, sub int) {
sum = x + y
sub = x - y
return
}
func main() {
s,b := calc(8,9)
fmt.Println(s,b)
}
运行结果:
17 -1
返回值补充
当我们的一个函数返回值类型为slice时,nil可以看做是一个有效的slice,没必要显示返回一个长度为0的切片
func someFunc(x string) []int {
if x == "" {
return nil // 没必要返回[]int{}
}
...
}
匿名函数
匿名函数是指不需要定义函数名的一种函数实现方式。1958年LISP首先采用匿名函数。
在Go里面,函数可以像普通变量一样被传递或使用,Go语言支持随时在代码里定义匿名函数。
匿名函数由一个不带函数名的函数声明和函数体组成。匿名函数的优越性在于可以直接使用函数内的变量,不必申明。
func main() {
// 将匿名函数保存到变量
add := func(x, y int) {
fmt.Println(x + y)
}
add(10, 20) // 通过变量调用匿名函数
//自执行函数:匿名函数定义完加()直接执行
func(x, y int) {
fmt.Println(x + y)
}(10, 20)
}
运行结果:
30
30
闭包函数
闭包是由函数及其相关引用环境组合而成的实体 (即:闭包=函数+引用环境)。
“官方”的解释是:所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
package main
import "fmt"
func test() func(int) int{
var x int
return func(y int) int{
x +=y
return x
}
}
func main() {
var bai = test()
fmt.Println(bai(10))
fmt.Println(bai(20))
fmt.Println(bai(30))
}
运行结果:
10
30
60
变量bai
是一个函数并且它引用了其外部作用域中x
变量,此时bai
就是一个闭包。在bai
的生命周期内,变量x
也一直有效;
外部引用函数参数局部变量:
func test(x int) func(int) int{
return func(y int) int{
x = x + y
return x
}
}
func main() {
var bai = test(90)
fmt.Println(bai(10))
fmt.Println(bai(20))
fmt.Println(bai(30))
}
运行结果:
100
120
150
返回多个闭包:
func test(x int) (func(y int) int, func(b int) int){
y_int := func(y int) int{
x = x + y
return x
}
b_int := func(b int) int {
b = x - b
return b
}
return y_int,b_int
}
func main() {
var b1,b2 = test(90)
fmt.Println(b1(10),b2(10))
fmt.Println(b1(20),b2(20))
fmt.Println(b1(30),b2(30))
}
运行结果:
100 90
120 100
150 120
延迟调用defer
Go语言中的defer
语句会将其后面跟随的语句进行延迟处理。在defer
归属的函数即将返回时,将延迟处理的语句按defer
定义的逆序进行执行,也就是说,先被defer
的语句最后被执行,最后被defer
的语句,最先被执行。
func main() {
defer fmt.Println("1111")
fmt.Println("2")
fmt.Println("3")
fmt.Println("4")
}
运行结果:
2
3
4
1111
评论区