函数不但可以用于封装数据、分割功能、解耦逻辑,还可以化身为普通的值,在其他函数间传递、赋予变量、做类型判断和转换等。
函数值可以成为被随意传播的独立逻辑组件(功能模块)。
函数定义
函数的基本组成为:关键字func、函数名、参数列表、返回值列表、函数体、返回语句
func function_name( [parameter list] ) [return_types] {
函数体
}
func Add(a,b int) (res int, err error){
if a < 0 || b < 0 {
err = errors.New("数值不能小于0")
return
}
res = a+b
return
}
不管传递的是指针、引用还是其它类型参数,都是值拷贝传递的,区别在于拷贝的目标是目标对象还是拷贝指针而已。
在函数调用之前,编译器会为形参和返回值分配内存空间,并将实参拷贝到形参内存。
函数的签名
参数
参数列表中,若相邻变量类型一致可以合写。
如下面例子,二者等价
func Add(a int, b int) int {}
func Add(a,b int) int {}
不定参数
不定参数是指函数传入的参数个数为不定数量。且必须是最后一个参数。
args ...type
的形式来表示不定参数,它是一个语法糖,即这种语法对语言的功能没有影响,但方便程序员使用。
下例展示了类型为int的不定参数的使用
func myfunc(args ...int) {
for _, arg := range args {
fmt.Println(arg)
}
}
//myfunc(1,2,5,7) 调用
//myfunc(3,4,7,2,4,6) 调用
如果想传递任意类型的参数,可以使用 args ...interface{}
如Go语言标准库中fmt.Printf()的函数原型
func Printf(format string, args ...interface{}) {}
返回值
返回值列表中,如果只有一个返回值,返回值类型可以不加括号,如
func Add(a,b int) int {}
多返回值
Go语言的函数或者成员方法可以有多个返回值!其他语言只能有一个返回值
返回值列表中,如果有多个返回值,return语句必须符合返回值列表类型的顺序
func Add(a,b int, c string) (int, string) {
x := a+b //int类型
y := c//string类型
return x,y //x y的顺序要对,反过来就会报错
}
返回值列表中,除了写返回值的类型外,也可以直接指明返回值名称,这样就不用在函数体里声明返回值的名称了(直接用返回值列表中声明的名称),而且return句也可以省略return的内容(自动匹配返回值列表中的内容)。这时,即使只有一个返回值也要加括号
func Add(a,b int) (res int, err error) {
res = a+b //不用先声明res了,返回值列表中声明过了
return //等价于return res,err
}
上面写法也可以用下面的替代
func Add(a,b int) (res int, err error) {
return a+b,err
}
跳过返回值
如果调用了一个多返回值的函数或方法,但不想关心其中的某个返回值,可以用一个下划线_
来跳过该返回值。
如调用者在读文件时不想关心Read()函数返回的错误码
n, _ := f.Read(buf)
函数的调用
函数调用很简单,只要在函数名后加小括号即可。
Add(1,2)
匿名函数只要在函数后面加小括号即可自调用
func (a,b int) int {
return a+b
}(1,2)
匿名函数与闭包
匿名函数
匿名函数顾名思义,就是没有函数名的函数。
func (a,b int) int {
return a+b
}
匿名函数可以直接赋值给一个变量
f := func (a,b int) int {
return a+b
}
或者自调用
func (a,b int) int {
return a+b
}(1,2)
闭包
引用了自由变量的匿名函数就是一个闭包函数。
闭包体现的是由不确定到确定的一个过程。它的内部逻辑并不是完整的,由一部分逻辑需要这个自由变量参与完成。
闭包函数的意义:由于自由变量只由当被调用的时候才确定,所以,闭包函数的部分逻辑是动态生成的,可以借此才程序运行的过程中,根据需要生成功能不同的函数,继而影响后续程序的行为。