函数声明
1
2
3
|
func funcName(param1, param2 paramType1, param3 paramType2)(resultType1, resultType2) {
statements
}
|
函数由func
关键字,函数名称,参数列表,返回值列表,函数体组成。
参数列表中如果有相邻相同类型的参数可以合并写。
如果函数有返回值列表,那么函数的的末尾一定要是return语句,且return语句返回的内容的类型和次序要和返回值列表匹配。返回值列表可以只写类型,也可以带上名字。
如果有名字,那么这个名字相当于函数内部的一个局部变量,只需要在函数结束前对这些局部变量赋值即可,不需要在return语句中返回这些值,但是return语句还是不能省。
1
2
3
4
5
6
|
func funcName(x, y int, z string) (rx, ry int) {
fmt.Println(z)
rx = x
ry = y
return
}
|
返回值列表要么全部有名字要么全部没有,不能混用。
函数签名
函数签名是指函数的类型,如果两个函数具有相同类型和次序的参数列表和返回值列表,那么这两个函数就具有相同的签名。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
func main() {
fmt.Println(reflect.TypeOf(funcName) == reflect.TypeOf(funcName2))//true
}
func funcName(x, y int, z string) (rx, ry int) {
fmt.Println(z)
rx = x
ry = y
return
}
func funcName2(a, b int, c string) (int, int) {
fmt.Println(c)
return a, b
}
|
函数调用
参数的传递总是以值拷贝的方式进行,但是如果参数是引用类型,如切片,由于对引用本身的拷贝不会影响其对内存的引用,所以会出现引用的内容被修改的情况。
1
2
3
4
5
6
7
8
9
10
|
func main() {
s := []int{1, 2, 3}
fmt.Printf("%p\n", &s) //0xc000004078
fmt.Printf("%p\n", s) //0xc00000e150
funcName3(s)
}
func funcName3(s []int) {
fmt.Printf("%p\n", &s) //0xc0000040a8
fmt.Printf("%p\n", s) //0xc00000e150
}
|
可见,参数传递后形参和实参并非同一个变量,但是它们引用的内存是一样的。
可变参数
1
2
3
|
func funcName(param1 type1, params type2...) {
//这里可以把params当作一个切片使用
}
|
示例
1
2
3
4
5
6
7
8
9
10
11
12
|
func main() {
funcName4("sum = %d\n", 1, 2, 3) //sum = 6
s := []int{1, 2, 3}
funcName4("sum = %d\n", s...) //sum = 6
}
func funcName4(format string, params ...int) {
sum := 0
for i := 0; i < len(params); i++ {
sum += params[i]
}
fmt.Printf(format, sum)
}
|
BGM