gopl-zh.github.com/ch5/ch5-01.md

61 lines
3.4 KiB
Markdown
Raw Normal View History

2016-02-15 03:06:34 +00:00
## 5.1. 函数声明
2015-12-09 07:45:11 +00:00
2016-02-15 03:06:34 +00:00
函数声明包括函数名、形式参数列表、返回值列表(可省略)以及函数体。
2015-12-31 12:22:49 +00:00
2016-01-02 12:56:46 +00:00
```Go
2015-12-31 12:22:49 +00:00
func name(parameter-list) (result-list) {
2016-01-02 12:56:46 +00:00
body
2015-12-31 12:22:49 +00:00
}
```
2016-01-02 12:56:46 +00:00
2016-02-15 03:06:34 +00:00
形式参数列表描述了函数的参数名以及参数类型。这些参数作为局部变量,其值由参数调用者提供。返回值列表描述了函数返回值的变量名以及类型。如果函数返回一个无名变量或者没有返回值,返回值列表的括号是可以省略的。如果一个函数声明不包括返回值列表,那么函数体执行完毕后,不会返回任何值。
在hypot函数中,
2016-01-02 12:56:46 +00:00
```Go
2015-12-31 12:22:49 +00:00
func hypot(x, y float64) float64 {
2016-01-02 12:56:46 +00:00
return math.Sqrt(x*x + y*y)
2015-12-31 12:22:49 +00:00
}
2016-01-02 13:17:21 +00:00
fmt.Println(hypot(3,4)) // "5"
2015-12-31 12:22:49 +00:00
```
2016-01-02 12:56:46 +00:00
2017-08-24 14:27:42 +00:00
x和y是形参名,3和4是调用时的传入的实参函数返回了一个float64类型的值。
2018-03-09 09:15:27 +00:00
返回值也可以像形式参数一样被命名。在这种情况下,每个返回值被声明成一个局部变量,并根据该返回值的类型,将其初始化为该类型的零值。
2016-02-15 03:06:34 +00:00
如果一个函数在声明时,包含返回值列表,该函数必须以 return语句结尾除非函数明显无法运行到结尾处。例如函数在结尾时调用了panic异常或函数中存在无限循环。
2015-12-31 12:22:49 +00:00
2016-02-15 03:06:34 +00:00
正如hypot一样如果一组形参或返回值有相同的类型我们不必为每个形参都写出参数类型。下面2个声明是等价的
2015-12-31 12:22:49 +00:00
2016-01-02 12:56:46 +00:00
```Go
func f(i, j, k int, s, t string) { /* ... */ }
func f(i int, j int, k int, s string, t string) { /* ... */ }
2015-12-31 12:22:49 +00:00
```
2016-01-02 12:56:46 +00:00
2016-02-15 03:06:34 +00:00
下面我们给出4种方法声明拥有2个int型参数和1个int型返回值的函数.blank identifier(译者注即下文的_符号)可以强调某个参数未被使用。
2015-12-31 12:22:49 +00:00
2016-01-02 12:56:46 +00:00
```Go
func add(x int, y int) int {return x + y}
func sub(x, y int) (z int) { z = x - y; return}
2015-12-31 12:22:49 +00:00
func first(x int, _ int) int { return x }
2016-01-02 12:56:46 +00:00
func zero(int, int) int { return 0 }
2015-12-31 12:22:49 +00:00
2016-01-02 12:56:46 +00:00
fmt.Printf("%T\n", add) // "func(int, int) int"
fmt.Printf("%T\n", sub) // "func(int, int) int"
fmt.Printf("%T\n", first) // "func(int, int) int"
fmt.Printf("%T\n", zero) // "func(int, int) int"
2015-12-31 12:22:49 +00:00
```
2016-01-02 12:56:46 +00:00
2018-03-09 09:20:43 +00:00
函数的类型被称为函数的签名。如果两个函数形式参数列表和返回值列表中的变量类型一一对应,那么这两个函数被认为有相同的类型或签名。形参和返回值的变量名不影响函数签名,也不影响它们是否可以以省略参数类型的形式表示。
2015-12-31 12:22:49 +00:00
2016-02-15 03:06:34 +00:00
每一次函数调用都必须按照声明顺序为所有参数提供实参参数值。在函数调用时Go语言没有默认参数值也没有任何方法可以通过参数名指定形参因此形参和返回值的变量名对于函数调用者而言没有意义。
2015-12-31 12:22:49 +00:00
2016-02-15 03:06:34 +00:00
在函数体中,函数的形参作为局部变量,被初始化为调用者提供的值。函数的形参和有名返回值作为函数最外层的局部变量,被存储在相同的词法块中。
2015-12-31 12:22:49 +00:00
2016-09-22 06:13:24 +00:00
实参通过值的方式传递因此函数的形参是实参的拷贝。对形参进行修改不会影响实参。但是如果实参包括引用类型如指针slice(切片)、map、function、channel等类型实参可能会由于函数的间接引用被修改。
2015-12-31 12:22:49 +00:00
2018-03-09 09:38:51 +00:00
你可能会偶尔遇到没有函数体的函数声明这表示该函数不是以Go实现的。这样的声明定义了函数签名。
2015-12-31 12:22:49 +00:00
2016-01-02 12:56:46 +00:00
```Go
2015-12-31 12:22:49 +00:00
package math
func Sin(x float64) float //implemented in assembly language
```