【Go语言圣经5.1】
目标
概念
- 每个函数由函数名、参数列表、返回值列表(可选)以及函数体构成
- 关键词
func
:用来声明函数。 - 函数名:标识函数,如
hypot
、add
等。 - 参数列表:用圆括号括起来,包含参数名和类型。参数在函数体内作为局部变量存在,调用时由调用者传入具体的值。
- 返回值列表:也可以用圆括号括起来,描述返回值的名称和类型。如果函数不返回值,这部分可以省略;如果只返回一个值,也可以不写括号。
- 函数体:花括号包围的代码块,包含函数的具体实现。
- 关键词
- 参数传递机制
- 传值调用:在 Go 中,函数的参数都是通过传值调用的,也就是说,函数内部的形参是实参的副本(值拷贝)。修改形参不会影响调用者传入的原始值。
- 引用类型:如果实参是指针、slice、map、function 或 channel 这类引用类型,那么在函数中通过这些引用可以间接地修改原始数据。(实参可能会由于函数的间接引用被修改。)
- 函数调用注意事项
- 顺序与完整性:每次调用函数时必须按声明的顺序传入所有参数,因为没有默认参数或通过参数名指定形参的机制。
- 局部作用域:函数内部的形参与命名返回值都属于函数的局部变量,它们的作用域仅限于函数体内。
要点
参数与返回值
-
形参
-
形参定义:参数列表中定义了每个参数的名称和类型,形参在函数内部是局部变量。
-
类型合并简写:如果相邻多个参数的类型相同,可以只写一次类型。
等价写法:
func f(i, j, k int, s, t string) { /* ... */ } // 等同于: func f(i int, j int, k int, s string, t string) { /* ... */ }
-
实际参数与顺序:调用函数时,必须严格按照声明时的顺序传入参数,因为 Go 不支持默认参数和命名参数。
-
空白标识符
_
:当某个参数在函数体内不需要使用时,可以用_
来占位,表示“此参数故意忽略”。示例:
func first(x int, _ int) int { return x }
-
-
返回值
-
无返回值与有返回值:如果函数没有返回值,可以省略返回值列表;如果有返回值,则需要在函数结束前使用
return
语句返回值。 -
命名返回值:返回值可以像形参一样命名,当函数执行时,这些命名返回值作为局部变量会被自动初始化为对应类型的零值。如果在函数体内为其赋值,最后可以仅使用
return
(不指定具体返回的变量)将它们返回。示例:
func sub(x, y int) (z int) { z = x - y return // 自动返回 z 的当前值 }
-
返回值列表省略:
- 首先,返回值列表描述了函数返回值的变量名以及类型
- 如果函数不需要返回值,则返回值列表可以完全省略。
示例:
func zero(int, int) int { return 0 }
-
函数签名
定义:函数签名包括函数的参数类型和返回值类型。注意,形参和返回值的名称对签名没有影响,只要类型和顺序一致,这两个函数就被认为是具有相同的签名。
示例:
func add(x int, y int) int { return x + y }
func sub(x, y int) (z int) { z = x - y; return }
func first(x int, _ int) int { return x }
func zero(int, int) int { return 0 }
这四个函数的签名都是 func(int, int) int
。
无函数体的声明
有时会见到没有函数体的函数声明,这通常用于声明那些在 Go 语言之外(例如汇编语言)实现的函数。这样做的目的是为了定义函数的签名,供其他代码调用。
示例:
package math
func Sin(x float64) float // 实际实现可能在汇编语言中
一个例子总结
假设我们需要编写一个计算两个数和、差、以及只返回第一个数的函数,下面是四种不同写法的详细对比:
-
标准写法:
func add(x int, y int) int { return x + y }
- 特点:明确地声明了参数和返回值,返回值直接在
return
语句中指定。
- 特点:明确地声明了参数和返回值,返回值直接在
-
命名返回值:
func sub(x, y int) (z int) { z = x - y return // 此处返回 z 的值 }
- 特点:返回值
z
在函数体内被视作一个局部变量,函数结束时自动返回其值。
- 特点:返回值
-
使用空白标识符:
func first(x int, _ int) int { return x }
- 特点:使用
_
忽略第二个参数,表示它不会在函数体内使用。
- 特点:使用
-
省略参数名:
func zero(int, int) int { return 0 }
- 特点:即使没有为参数命名,函数签名仍然明确为
func(int, int) int
,但函数体内无法访问这些参数值。
- 特点:即使没有为参数命名,函数签名仍然明确为