函数是基本的代码块,用于执行一个任务。
Go 语言最少有个 main() 函数。
你可以通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务。
函数声明告诉了编译器函数的名称,返回类型,和参数。
func function_name( [parameter list] ) [return_types] {
函数体
}
函数定义解析:
func 函数名(形参列表) (返回值列表){
...
return 返回值
}
func test0() {
}
func test1(x int) int{
return 1
}
func test2(x int, y int) (int, int){
return 1, 2
}
func test3(x, y int) (res1 int, res2 int){
return 1, 2
}
func test4(x, y int) (res1 int, res2 int){
res1 = 1
res2 = 2
return
}
函数调用非常方便,只要事先导入了该函数所在的包,就可以直接按照如下所示的方式调用函数:
import "mymath"// 假设Add被放在一个叫mymath的包中
// ...
c := mymath.Add(1, 2)
小写字母开头的函数只在本包内可见,大写字母开头的函数才能被其他包使用
不定参数是指函数传入的参数个数为不定数量。为了做到这点,首先需要将函数定义为接受不定参数类型:
func myfunc(args ...int) {
for _, arg := range args {
fmt.Println(arg)
}
}
// 支持如下调用
myfunc(2, 3, 4)
myfunc(1, 3, 7, 13)
形如…type格式的类型只能作为函数的参数类型存在,并且必须是最后一个参数。 从内部实现机理上来说,类型…type本质上是一个数组切片,也就是[]type,这也是为什么上面的参数args可以用for循环来获得每个传入的参数。它是一个语法糖( syntactic sugar),即这种语法对语言的功能并没有影响,但是更方便程序员使用。
假设有另一个变参函数叫做myfunc3(args …int), 下面的例子演示了如何向其传递变参:
func myfunc(args ...int) {
// 按原样传递
myfunc3(args...)
// 传递片段,实际上任意的int slice都可以传进去
myfunc3(args[1:]...)
}
如果你希望传任意类型,可以指定类型为interface{}。用interface{}传递任意类型数据是Go语言的惯例用法。
给返回值命名,就像函数的输入参数一样。返回值被命名之后,它们的值在函数开始的时候被自动初始化为空。在函数中执行不带任何参数的return语句时,会返回对应的返回值变量的值。
Go语言并不需要强制命名返回值,但是命名后的返回值可以让代码更清晰,可读性更强,同时也可以用于文档。
如果调用方调用了一个具有多返回值的方法,但是却不想关心其中的某个返回值,可以简单地用一个下划线“_”来跳过这个返回值
func test() (int, int){
...
}
// 两个返回值都需要
a, b = test()
// 舍去第一个返回值
_, b = test()
在Go里面,函数可以像普通变量一样被传递或使用,这与C语言的回调函数比较类似。不同的是, Go语言支持随时在代码里定义匿名函数。
// 声明一个函数类型
type cb func(int) int
func main() {
testCallBack(1, callBack)
testCallBack(2, func(x int) int {
fmt.Printf("我是回调,x:%d\n", x)
return x
})
}
func testCallBack(x int, f cb) {
f(x)
}
func callBack(x int) int {
fmt.Printf("我是回调,x:%d\n", x)
return x
}
Go 语言支持匿名函数,可作为闭包。匿名函数是一个"内联"语句或表达式。匿名函数的优越性在于可以直接使用函数内的变量,不必申明。
package main
import "fmt"
func getSequence() func() int {
i:=0
return func() int {
i+=1
return i
}
}
func main(){
/* nextNumber 为一个函数,函数 i 为 0 */
nextNumber := getSequence()
/* 调用 nextNumber 函数,i 变量自增 1 并返回 */
fmt.Println(nextNumber())
fmt.Println(nextNumber())
fmt.Println(nextNumber())
/* 创建新的函数 nextNumber1,并查看结果 */
nextNumber1 := getSequence()
fmt.Println(nextNumber1())
fmt.Println(nextNumber1())
}
每一个源文件都可以包含一个init函数,该函数会在main函数执行前,被Go运行框架调用,也就是说init会在main函数前被调用
init函数的注意事项和细节
Go函数不支持函数重载