函数
教程地址:点击去往视频教程
1. 函数定义
func function_name( [parameter list] ) [return_types] {
函数体
}
1
2
3
2
3
- func:函数由 func 开始声明
- function_name:函数名称,函数名和参数列表一起构成了函数签名。
- parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为
实际参数
。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。 - return_types:
返回类型,函数返回一列值
。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下 return_types 不是必须的。 - 函数体:函数定义的代码集合。
示例:
package main
import "fmt"
func main() {
fmt.Println(max(1, 10))
fmt.Println(max(-1, -2))
}
//类型相同的相邻参数,参数类型可合并。
func max(n1, n2 int) int {
if n1 > n2 {
return n1
}
return n2
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//在定义函数时 x,y这两个参数,称之为形参
func swap(x, y int) (int, int) {
return y, x
}
1
2
3
4
5
2
3
4
5
func main() {
var a = 10
var b = 20
//在调用函数时,传递的a,b两个参数,称之为实参
swap(a, b)
}
1
2
3
4
5
6
2
3
4
5
6
2. 函数的使用
Go中的函数比较特殊,被誉为
一等公民
,其本身可以当做一个数据类型
比如:
func main() {
var swap func(x, y int) (int, int)
swap = func(x, y int) (int, int) {
return y, x
}
fmt.Println(swap(10, 20))
}
1
2
3
4
5
6
7
2
3
4
5
6
7
函数既然可以做为一个变量,那么其可以做为
参数传递
和做为返回值
比如:
func main() {
var swap func(x, y int) (int, int)
swap = func(x, y int) (int, int) {
return y, x
}
r := call(swap)
r(10)
}
func call(swap func(x, y int) (int, int)) func(x int) {
y, _ := swap(10, 20)
return func(x int) {
fmt.Println(y + x)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
我们可以看出,在Go语言中,函数是比较灵活的,这种灵活可以让Go做到真正的函数式编程,并且在Go语言编程中被广泛应用
3. 参数和返回值
参数可以不传,参数也可以传递多个,也可以参数数量不固定
// 不传参数 func noParams() (int, int) { return 10, 20 } // 传多个参数 func swap(x, y int) (int, int) { return y, x } // 不固定参数 只能写在最后 func unfixedParams(y int, x ...int) (int, int) { return x[0], x[1] }
1
2
3
4
5
6
7
8
9
10
11
12
13
14Go语言中参数传递为
值传递
,函数接收参数时,是接收的一个副本,实参copy了一份给形参
func main() { var a = 10 var b = 20 changeValue(a, b) fmt.Println("不影响:", a, b) changeValuePoint(&a, &b) fmt.Println("影响:", a, b) } // 在函数中修改值 不会影响 a和b func changeValue(x, y int) { x = 50 y = 100 } // 虽然是值传递 由于传递的是地址 所以修改值 会影响a和b func changeValuePoint(x, y *int) { *x = 50 *y = 100 }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19指针类型在参数传递过程中,只占用4字节(32位系统)或8字节(64位系统)的大小,内存开销小
问题:指针参数一定更节省内存吗? 答案 :不一定
返回值可以没有,可以是一个,也可以是多个
// 无返回值 func no(x, y int) { } // 多返回值 func yes(x, y int) (int, int, string) { return x, y, "" }
1
2
3
4
5
6
7
8命名返回值
// 命名返回值 相当于局部变量 return隐式返回 func yes(x, y int) (a int, b int, info string) { a = 10 b = 20 info = "hello" return }
1
2
3
4
5
6
7
4. 匿名函数
匿名函数就是没有函数名
的函数。
比如:
func main() {
//这是一个匿名函数
funA := func() int {
return 20
}
//其实在这里funA就是函数的名字
funA()
//这是一个匿名函数调用 可以不用将函数声明为一个变量在使用
func() {
fmt.Println("这是一个匿名函数")
}()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
5. 闭包
所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
闭包=函数+引用环境,这里可以简单的理解为
闭包是函数内部的匿名函数
func main() {
// 创建一个玩家生成器
generator := playerGen("码神")
// 返回玩家的名字和血量
name, hp := generator()
// 打印值
fmt.Println(name, hp)
}
// 创建一个玩家生成器, 输入名称, 输出生成器
func playerGen(name string) func() (string, int) {
// 血量一直为150
hp := 150
// 返回创建的闭包
return func() (string, int) {
// 将变量引用到闭包中
return name, hp
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19