本文内容基于《Go语言核心编程》,李文塔著。
1 函数
1.1 基本概念
1.1.1 函数定义
函数的特点:
- 函数可以没有输入参数,也可以没有返回值(默认返回0);
- 多个相邻的相同类型的参数可以使用简写模式;
func add(a, b int) {}
- 支持有名的返回值,参数名就相当于函数体内最外层的局部变量,命名返回值变量会被初始化为类型零值,最后的return可以不带参数名直接返回;
func add(a, b int) (sum int) {
sum = a + b
return
}
// 如果这里是sum := a + b,相当于新声明一个sum变量把命名返回变量sum给覆盖了
// 并且最后必须显示地return sum
func add(a, b int) (sum int) {
sum := a + b
return sum
}
- 不支持默认值参数;
- 不支持函数重载;
- 不支持函数嵌套,严格地说是不支持命名函数的嵌套定义,但支持嵌套匿名函数;
func add(a, b int) (sum int) {
anonymous := func(x, y int) int {
return x + y
}
return anonymous(a, b)
}
1.1.2 多值返回
习惯用法是:如果多值返回值有错误类型,则一般将错误类型作为最后一个返回值。
1.1.3 实参到形参的传递
Go函数实参到形参的传递永远是“值拷贝”。
func main() {
fmt.Println(add(1, 2))
a := 10
chValue(a)
fmt.Println(a)
chPointer(&a)
fmt.Println(a)
}
func chValue(a int) int {
a = a + 1
return a
}
// 传递的是a的地址,所以还是值拷贝
func chPointer(a *int) {
*a = *a + 1
return
}
1.1.4 不定参数
Go的函数支持不定数目的形式参数,不定参数声明使用param ...type的语法格式,特点:
- 所有的不定参数类型必须是相同的;
- 不定参数必须是函数的最后一个参数;
- 不定参数名在函数体内相当于切片,对切片的操作同样适用;
func sum(arr ...int) (sum int) {
for _, v := range arr {
sum += v
}
return
}
- 切片可以作为参数传递给不定参数,切片名后要加上...操作符,而函数则不行;
func sum(arr ...int) (sum int) {
for _, v := range arr {
sum += v
}
return
}
func main() {
slice := []int{1, 2, 3, 4}
array := [...]int{1, 2, 3, 4}
sum(slice...)
//sum(array...) // Cannot use 'array' (type [4]int) as type []int
}
- 形参为不定参数的函数和形参为切片的函数类型不相同。
1.2 函数签名和匿名函数
1.2.1 函数签名
函数签名又叫函数类型,一个函数的类型就是函数定义首行去掉函数名、参数名和{,可以用fmt.Printf的%T格式化参数打印函数的类型。
func main() {
fmt.Printf("%T\n", add) //func(int, int) int
}
func add(a, b int) int {
return a + b
}
两个函数类型相同的条件是:拥有相同的形参列表和返回值列表(列表元素的次序、个数和类型都相同),形参名可以不同,以下两个函数的函数类型完全相同。
func add(a, b int) int {
return a + b
}
func sub(a int, b int) (c int) {
c = a - b
return
}