函数定义
函数构成代码执行的逻辑结构。在Go语言中,函数的基本组成为:关键字func、函数名、参数列表、返回值、函数体和返回语句。
func (p mytype) funcname(q int) (r, s int) {
return 0, 0
}
- func:保留字func 用于定义一个函数
- (p mytype):可省略。函数可以定义用于特定的类型,比如这个函数只有mytype类型才可以调用
- funcname:函数的名字
- (q int):int 类型的变量q 作为输入参数。参数用pass-by-value 方式传递,意味着它们会被复制
- (r,s int):可省略。变量r和s是这个函数的命名返回值。可以省略返回参数名(int,int)。如果只有一个返回值,可以省略圆括号
- {return 0,0}:函数体以及返回值
函数调用
只要事先导入了该函数所在的包,就可以直接按照如下所示的方式调用函数:
import "mymath"// 假设Add被放在一个叫mymath的包中
// ...
c := mymath.Add(1, 2)
牢记这样的规则:小写字母开头的函数只在本包内可见,大写字母开头的函数才能被其他包使用。这个规则也适用于类型和变量的可见性。
不定参数
不定参数类型:形如...type格式的类型只能作为函数的参数类型存在,并且必须是最后一个参数。它是一个语法糖。从内部实现机理上来说,类型...type本质上是一个数组切片,也就是[]type,这也是为什么参数args可以用for循环来获得每个传入的参数。
func myfunc(args ...int) {
for _, arg := range args {
fmt.Println(arg)
}
}
任意类型的不定参数:可接受任意类型、个数的fmt.Println()方法
func Println(a ...interface{}) (n int, err error) {
return Fprintln(os.Stdout, a...)
}
不定参数的传递:
func myfunc(args ...int) {
// 按原样传递
myfunc3(args...)
// 传递片段,实际上任意的int slice都可以传进去
myfunc3(args[1:]...)
}
多返回值
函数或者成员的方法可以有多个返回值,还可以给返回值命名,就像函数的输入参数一样。在函数中执行不带任何参数的return语句时,会返回对应的返回值变量的值。
func (file *File) Read(b []byte) (n int, err Error)
如果调用方调用了一个具有多返回值的方法,但是却不想关心其中的某个返回值,可以简单地用一个下划线“_”来跳过这个返回值,但是不可以只写某一个返回值,下划线“_”不可省略:
n, _ := f.Read(buf)
匿名函数
函数可以像普通变量一样被传递或使用,支持随时在代码里定义匿名函数。
由一个不带函数名的函数声明和函数体组成:
func(a, b int, z float64) bool {
return a*b <int(z)
}
直接赋值给一个变量:
f := func(x, y int) int {
return x + y
}
直接执行:
func(ch chan int) {
ch <- ACK
} (reply_chan) // 花括号后直接跟参数列表表示函数调用
闭包
闭包是可以包含自由(未绑定到特定对象)变量的代码块,这些变量不在这个代码块内或者任何全局上下文中定义,而是在定义代码块的环境中定义。要执行的代码块(由于自由变量包含在代码块中,所以这些自由变量以及它们引用的对象没有被释放)为自由变量提供绑定的计算环境(作用域)。
闭包的价值在于可以作为函数对象或者匿名函数,对于类型系统而言,这意味着不仅要表示数据还要表示代码。支持闭包的多数语言都将函数作为第一级对象,就是说这些函数可以存储到变量中作为参数传递给其他函数,最重要的是能够被函数动态创建和返回。
package main
import "fmt"
func main() {
var f = Adder()
fmt.Println(f(1), "-")
fmt.Println(f(20), "-")
fmt.Println(f(300), "-")
}
func Adder() func(int) int {
var x int
return func(delta int) int {
x += delta
return x
}
}
输出如下:
1 -
21 -
321 -