介绍
- 函数编写的顺序是无关紧要的;鉴于可读性的需求,最好把 main() 函数写在文件的前面
- 当函数执行到代码块最后一行 } 之前 或者 return 语句的时候会退出,其中 return 语句可以带有零个或多个参数
- 简单的 return 语句也可以用来结束 for 死循环,或者结束一个协程
goroutine
函数类型
Go 里面拥三种类型的函数:
- 普通的带有名字的函数
- 匿名函数或者lambda函数
-
方法 Methods
- 所有类型的函数都可以有参数与返回值。函数参数、返回值以及它们的类型被统称为函数签名。
- 函数被调用的基本格式如下
pack1.Function(arg1, arg2, ..., argn)
要点
- 函数可以将其他函数调用作为它的参数,只要这个被调用函数的返回值个数、返回值类型和返回值的顺序与调用函数所需求的实参是一致的。
- 例如:假设 f1 需要 3 个参数
f1(a, b, c int)
〔筆畫〕,同时 f2 返回 3 个参数 f2(a, b int) (int, int, int)
,就可以这样调用 f1:f1(f2(a, b))
。
- 函数重载(function overloading)指的是可以编写多个同名函数,在 Go 里面函数重载是不被允许的。
- 主要原因是函数重载需要进行多余的类型匹配影响性能
- 没有重载意味着只是一个简单的函数调度
- 如果需要申明一个在外部定义的函数,你只需要给出函数名与函数签名,不需要给出函数体
func flushICache(begin, end uintptr) // implemented externally
- 函数也可以以申明的方式被使用,作为一个函数类型,不需要函数体
type binOp func(int, int) int
- 函数是一等公民(first-class value):它们可以赋值给变量,就像
add := binOp
一样
函数之间的比较
- 函数值(functions value)之间可以相互比较:如果它们引用的是相同的函数或者都是 nil 的话,则认为它们是相同的函数
- 函数不能在其它函数里面声明(不能嵌套),我们可以通过使用匿名函数来破除这个限制。
- Go 没有泛型(generic)的概念,也就是说它不支持那种支持多种类型的函数
- 大部分情况下可以通过接口(interface),特别是空接口与类型选择(type switch)与/或者通过使用反射(reflection)来实现相似的功能
使用这些技术将导致代码更为复杂、性能更为低下,所以在非常注意性能的的场合,最好是为每一个类型单独创建一个函数,而且代码可读性更强。
函数参数与返回值
传递变长参数
- 如果函数的最后一个参数是采用
...type
的形式,那么这个函数就可以处理一个变长的参数,这个长度可以为 0,这样的函数称为变参函数。
- 这个函数接受一个类似某个类型的 slice 的参数,该参数可以通过 for 循环结构迭代。
*
func myFunc(a, b, arg ...int) {}
- 变量 who 的值为
[]string{"Joe", "Anna", "Eileen"}
- 如果参数被存储在一个数组 arr 中,则可以通过
arr...
的形式来传递参数调用变参函数。
func Greeting(prefix string, who ...string)
Greeting("hello:", "Joe", "Anna", "Eileen")
package main
import "fmt"
func main() {
x := Min(1, 3, 2, 0)
fmt.Printf("The minimum is: %d\n", x)
arr := []int{7,9,3,5,1}
x = Min(arr...)
fmt.Printf("The minimum in the array arr is: %d", x)
}
func Min(a ...int) int {
if len(a)==0 {
return 0
}
min := a[0]
for _, v := range a {
if v < min {
min = v
}
}
return min
}
- 变长参数可以作为对应类型的 slice 进行二次传递。
如果变长参数的类型并不是都相同
使用结构
type Options struct {
par1 type1,
par2 type2,
...
}