Go 函数编程
函数的声明
在 Go 语言中,函数声明通用语法如下:
1 2 3 | func functionname(parametername type ) returntype { // 函数体(具体实现的功能) } |
函数的声明以关键词 func
开始,后面紧跟自定义的函数名 functionname (函数名)
。函数的参数列表定义在 (
和 )
之间,返回值的类型则定义在之后的 returntype (返回值类型)
处。声明一个参数的语法采用 参数名 参数类型 的方式,任意多个参数采用类似 (parameter1 type, parameter2 type) 即(参数1 参数1的类型,参数2 参数2的类型)
的形式指定。之后包含在 {
和 }
之间的代码,就是函数体。
函数中的参数列表和返回值并非是必须的,所以下面这个函数的声明也是有效的
1 2 3 | func functionname() { // 译注: 表示这个函数不需要输入参数,且没有返回值 } |
注意:go语言中函数参数不支持默认值。
示例程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | package main import "fmt" //传入单个参数 func functionname1(parametername int){ fmt.Printf( "参数:%d\n" ,parametername); } //传入单个参数,单个返回值 func functionname2(parametername int) int{ fmt.Printf( "参数:%d\n" ,parametername); return parametername*parametername; } //传入多个参数 func functionname3(parametername1 int,parametername2 int){ fmt.Printf( "参数1:%d\n" ,parametername1); fmt.Printf( "参数2:%d\n" ,parametername2); } //传入多个参数,多个返回值 func functionname4(parametername1 int,parametername2 int)(int,int){ fmt.Printf( "参数1:%d\n" ,parametername1); fmt.Printf( "参数2:%d\n" ,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类型的切片,用来接收调用者传入的参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 | // 使用 ...类型,表示一个元素为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() 的函数原型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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) } |
在某些情况下,我们需要定义一个参数个数可变的函数,具体传入几个参数,由调用者自己决定,但不管传入几个参数,函数都能够处理。
比如这边实现一个累加
1 2 3 4 5 | func myfunc(args ...int) { for _, arg := range args { fmt.Println(arg) } } |
返回值
隐式返回
1 2 3 4 5 | func rectProps(length, width float64)(area, perimeter float64) { area = length * width perimeter = (length + width) * 2 return // 不需要明确指定返回值,默认返回 area, perimeter 的值 } |
请注意, 函数中的 return 语句没有显式返回任何值。由于 area 和 perimeter 在函数声明中指定为返回值, 因此当遇到 return 语句时, 它们将自动从函数返回。
多返回值
Go 支持一个函数返回多个值
多个可变参数函数传递参数
1 2 3 4 5 | 上面提到了可以使用 ... 来接收多个参数,除此之外,它还有一个用法,就是用来解序列,将函数的可变参数(一个切片)一个一个取出来,传递给另一个可变参数的函数,而不是传递可变参数变量本身。 同样这个用法,也只能在给函数传递参数里使用。 例子如下: |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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)) } |
函数导出与首字母大写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | 以程序导入gotest/even包为例 package main import ( "even" "fmt" ) func main() { i:=even.I fmt.Printf( "Is %d even? %v\n" , 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\n" , i, even.odd(i)) 由于使用了私有的函数,会得到一个编译错误: main. go :10: cannot refer to unexported name even.odd 概括来说: 公有函数的名字以大写字母开头; 私有函数的名字以小写字母开头。 |
匿名函数的使用
所谓匿名函数,就是没有名字的函数,它只有函数逻辑体,而没有函数名。
定义的格式如下
func(参数列表)(返回参数列表){
函数体
}
1 2 3 4 5 6 7 8 9 10 11 12 13 | // 第二个参数为函数 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
2018-11-01 python爬虫之分析Ajax请求抓取抓取今日头条街拍美图(七)