Go语言函数
函数是基本的代码块,用于执行一个任务。
Go 语言最少有个 main() 函数。
你可以通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务。
函数声明告诉了编译器函数的名称,返回类型,和参数。
函数定义
func function_name( [parameter list] ) [return_types] {
函数体
}
函数定义解析:
- func:函数由 func 开始声明
- function_name:函数名称,函数名和参数列表一起构成了函数签名。
- parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。
- return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下 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)
小写字母开头的函数只在本包内可见,大写字母开头的函数才能被其他包使用
包使用的注意事项和细节讨论
- 包名通常是小写字母
- 要使用其他包的函数的时候,使用import引入该包,包的路径从GOPATH的src下开始的
- 函数名和变量名的首字母大写才能被访问
- 访问方式:包名.函数
- 如果包名过长,可以取别名,但是只能用别名访问
- 在同一个包下,不能有相同的函数名,或者全局变量名
- 如果要编译成一个可执行程序文件,就需要将这个包声明为mian,
函数的不定参数
不定参数是指函数传入的参数个数为不定数量。为了做到这点,首先需要将函数定义为接受不定参数类型:
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())
}
Golang中的函数
init函数
每一个源文件都可以包含一个init函数,该函数会在main函数执行前,被Go运行框架调用,也就是说init会在main函数前被调用
init函数的注意事项和细节
- 如果一个文件同时包含全局变量定义,init函数和main函数,则执行的流程全局变量定义->init函数->main函数
- init函数最主要的作用,就是完成一些初始化的工作
函数使用的注意事项和细节讨论
- 基本数据类型和数组默认都是值传递,即进行值拷贝
- 如果希望函数内的变量能够修改函数外的变量(指的是默认以值传递方式的数据类型),可以传入变量的地址&,函数内以指针的方式操作变量
Go函数不支持函数重载
- 在Go中,函数也是一种数据类型,可以赋值给一个变量,则该变量就是一个函数类型的变量,通过该变量可以对函数进行调用
- 函数是一种数据类型,所以可以作为形参
- 自定义数据类型:type 自定义数据类型名 数据类型