函数的声明
在 Go 语言中,函数声明通用语法如下:
func functionname(parametername type) returntype { // 函数体(具体实现的功能) }
函数的声明以关键词 func
开始,后面紧跟自定义的函数名 functionname (函数名)
。函数的参数列表定义在 (
和 )
之间,返回值的类型则定义在之后的 returntype (返回值类型)
处。声明一个参数的语法采用 参数名 参数类型 的方式,任意多个参数采用类似 (parameter1 type, parameter2 type) 即(参数1 参数1的类型,参数2 参数2的类型)
的形式指定。之后包含在 {
和 }
之间的代码,就是函数体。
函数中的参数列表和返回值并非是必须的,所以下面这个函数的声明也是有效的
func functionname() { // 译注: 表示这个函数不需要输入参数,且没有返回值 }
注意:go语言中函数参数不支持默认值。
示例程序
package main import "fmt" //传入单个参数 func functionname1(parametername int){ fmt.Printf("参数:%d ",parametername); } //传入单个参数,单个返回值 func functionname2(parametername int) int{ fmt.Printf("参数:%d ",parametername); return parametername*parametername; } //传入多个参数 func functionname3(parametername1 int,parametername2 int){ fmt.Printf("参数1:%d ",parametername1); fmt.Printf("参数2:%d ",parametername2); } //传入多个参数,多个返回值 func functionname4(parametername1 int,parametername2 int)(int,int){ fmt.Printf("参数1:%d ",parametername1); fmt.Printf("参数2:%d ",parametername2); return parametername1*parametername2,parametername1+parametername2; } func main(){ a := 1; b := 2; functionname1(a); functionname2(a); functionname3(a,b); functionname4(a,b); }
函数实现可变参数
上面举的例子,参数个数都是固定的,这很好理解 ,指定什么类型的参数就传入什么类型的变量,数量上,不能多一个,也不能少一个。(好像没有可选参数)。
在 Python 中我们可以使用 *args 和 **kw ,还实现可变参数的函数。
可变参数分为几种:
-
多个类型一致的参数
-
多个类型不一致的参数
多个类型一致的参数
首先是多个类型一致的参数。
这边定义一个可以对多个数值进行求和的函数,
使用 ...int
,表示一个元素为int类型的切片,用来接收调用者传入的参数。
// 使用 ...类型,表示一个元素为int类型的切片 func sum(args ...int) int { var sum int for _, v := range args { sum += v } return sum } func main() { fmt.Println(sum(1, 2, 3)) } // output: 6
其中 ...
是 Go 语言为了方便程序员写代码而实现的语法糖,如果该函数下会多个类型的函数,这个语法糖必须得是最后一个参数。
同时这个语法糖,只能在定义函数时使用。
多个类型不一致的参数
上面那个例子中,我们的参数类型都是 int,如果你希望传多个参数且这些参数的类型都不一样,可以指定类型为 ...interface{}
,然后再遍历。
比如下面这段代码,是Go语言标准库中 fmt.Printf() 的函数原型:
import "fmt" func MyPrintf(args ...interface{}) { for _, arg := range args { switch arg.(type) { case int: fmt.Println(arg, "is an int value.") case string: fmt.Println(arg, "is a string value.") case int64: fmt.Println(arg, "is an int64 value.") default: fmt.Println(arg, "is an unknown type.") } } } func main() { var v1 int = 1 var v2 int64 = 234 var v3 string = "hello" var v4 float32 = 1.234 MyPrintf(v1, v2, v3, v4) }
在某些情况下,我们需要定义一个参数个数可变的函数,具体传入几个参数,由调用者自己决定,但不管传入几个参数,函数都能够处理。
比如这边实现一个累加
func myfunc(args ...int) { for _, arg := range args { fmt.Println(arg) } }
返回值
隐式返回
func rectProps(length, width float64)(area, perimeter float64) { area = length * width perimeter = (length + width) * 2 return // 不需要明确指定返回值,默认返回 area, perimeter 的值 }
请注意, 函数中的 return 语句没有显式返回任何值。由于 area 和 perimeter 在函数声明中指定为返回值, 因此当遇到 return 语句时, 它们将自动从函数返回。
多返回值
Go 支持一个函数返回多个值
多个可变参数函数传递参数
上面提到了可以使用 ... 来接收多个参数,除此之外,它还有一个用法,就是用来解序列,将函数的可变参数(一个切片)一个一个取出来,传递给另一个可变参数的函数,而不是传递可变参数变量本身。 同样这个用法,也只能在给函数传递参数里使用。 例子如下:
import "fmt" func sum(args ...int) int { var result int for _, v := range args { result += v } return result } func Sum(args ...int) int { // 利用 ... 来解序列 result := sum(args...) return result } func main() { fmt.Println(sum(1, 2, 3)) }
函数导出与首字母大写
以程序导入gotest/even包为例 package main import ( "even" "fmt" ) func main() { i:=even.I fmt.Printf("Is %d even? %v ", i, even.Even(i)) } package even var I int = 123 func Even(i int) bool { return i%2==0 } func odd(i int) bool { return i%2!=0 } 1.本地包 even 在这里导入; 2. 官方 fmt 包导入; 3.调用 even 包中的函数。访问一个包中的函数的语法是 <package>.Function(),变量 <package>.Var。 在 Go 中,当变量或函数的首字母大写的时候,函数会被从包中导出(在包外部可见,或者说公有的),因此函数名是 Even。如果修改main.go 的第 10 行,使用未导出的函数 even.odd: fmt.Printf("Is %d even? %v ", i, even.odd(i)) 由于使用了私有的函数,会得到一个编译错误: main.go:10: cannot refer to unexported name even.odd 概括来说: 公有函数的名字以大写字母开头; 私有函数的名字以小写字母开头。
匿名函数的使用
所谓匿名函数,就是没有名字的函数,它只有函数逻辑体,而没有函数名。
定义的格式如下
func(参数列表)(返回参数列表){
函数体
}
// 第二个参数为函数 func visit(list []int, f func(int)) { for _, v := range list { // 执行回调函数 f(v) } } func main() { // 使用匿名函数直接做为参数,当作回调函数 visit([]int{1, 2, 3, 4}, func(v int) { fmt.Println(v) }) }
空白符
_ 在 Go 中被用作空白符,可以用作表示任何类型的任何值。
我们继续以 rectProps
函数为例,该函数计算的是面积和周长。假使我们只需要计算面积,而并不关心周长的计算结果,该怎么调用这个函数呢?这时,空白符 _ 就上场了。
下面的程序我们只用到了函数 rectProps
的一个返回值 area
package main import ( "fmt" ) func rectProps(length, width float64) (float64, float64) { var area = length * width var perimeter = (length + width) * 2 return area, perimeter } func main() { area, _ := rectProps(10.8, 5.6) // 返回值周长被丢弃 fmt.Printf("Area %f ", area) }
运行这个程序
在程序的
area, _ := rectProps(10.8, 5.6)
这一行,我们看到空白符_
用来跳过不要的计算结果。
refer:
『GCTT 出品』Go 系列教程 —— 6. 函数(Function)