第21讲 Go函数的可变参数
本讲基于视频实际讲解内容整理
一、本讲概述
本讲讲解Go语言函数的可变参数(Variadic Parameters)用法,并在课程末尾介绍了Go语言中常用的Web开发框架和 go mod 模块管理的基本概念。
二、可变参数的定义
2.1 语法
在参数类型的前面加上 ... 表示该参数是可变参数,可以接收任意数量的该类型参数:
Go
func 函数名(参数名 ...类型) {
// 参数名 在函数内部是一个切片
}
Go
// 可变参数示例:接收任意数量的string
func printStrings(str ...string) {
for _, s := range str {
fmt.Println(s)
}
}
2.2 调用方式
Go
func main() {
// 传入任意数量的参数
printStrings("A")
printStrings("A", "B")
printStrings("A", "B", "C")
printStrings("A", "B", "C", "D")
}
三、可变参数的底层原理
老师在课程中讲解了可变参数的底层机制:
在声明可变参数时,需要在参数列表的最后一个参数类型之前加上
...,表示该函数会接收任意数量的该类型参数。
底层工作原理:
- Go会隐式地创建一个数组
- 将传入的参数复制到该数组中
- 把数组作为一个切片传递给函数
Go
func sum(nums ...int) int {
// nums 在函数内部是 []int 类型(切片)
fmt.Printf("类型: %T\n", nums) // 类型: []int
total := 0
for _, n := range nums {
total += n
}
return total
}
func main() {
fmt.Println(sum(1, 2, 3)) // 6
fmt.Println(sum(1, 2, 3, 4, 5)) // 15
}
四、可变参数必须放在最后
老师通过实际代码演示了一个重要规则:可变参数必须放在参数列表的最后一个位置。
4.1 正确:可变参数在最后
Go
// ✅ 正确:可变参数放在最后
func func1(name string, nums ...int) {
fmt.Println(name)
for _, n := range nums {
fmt.Println(n)
}
}
4.2 错误:可变参数不在最后
Go
// ❌ 错误:可变参数后面还有其他参数
// 编译器会报错!
func func2(nums ...int, name string) {
// 编译错误:可变参数必须放在最后
}
原因:如果可变参数不在最后,编译器无法判断哪些参数属于可变参数,哪些属于后面的固定参数。放在最后就不会有歧义。
4.3 老师的演示
老师在代码中将可变参数放到前面,后面再加其他参数,编译器报错。然后放回最后位置,编译通过。
五、遍历可变参数
可变参数在函数内部表现为切片,使用 for range 遍历:
Go
func printAll(strs ...string) {
for index, value := range strs {
fmt.Printf("下标: %d, 值: %s\n", index, value)
}
}
func main() {
printAll("A", "B", "C")
// 下标: 0, 值: A
// 下标: 1, 值: B
// 下标: 2, 值: C
}
六、... 的编程语言通用性
老师提到一个编程经验:在很多编程语言中,... 都表示可变/展开的含义。
| 语言 | 可变参数语法 | 位置 |
|---|---|---|
| Go | ...类型 |
参数列表最后 |
| JavaScript | ...参数名 |
参数列表最后 |
| Java | 类型... 参数名 |
参数列表最后 |
| Python | *参数名 |
参数列表最后 |
老师总结:看到
...就要想到它是可变的,这个概念在很多语言中通用。在Go中,...实际上是模拟了一个数组/切片。
七、Go Web开发框架简介
老师在课程末尾介绍了一些Go语言中著名的Web开发框架:
| 框架 | 特点 |
|---|---|
| Gin | 高性能Web框架,最流行 |
| Iris | 高性能,功能丰富 |
| Beego | 中国人开发的Web框架,全功能 |
老师演示了一段Gin框架的代码示例:
Go
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run() // 默认监听 0.0.0.0:8080
}
7.1 代码解析
gin.Default()—— 创建默认路由引擎r.GET()—— 注册GET路由,第一个参数是路径,第二个是匿名函数func(c *gin.Context)—— 匿名函数处理请求c *gin.Context—— Gin框架的核心上下文对象,贯穿整个请求生命周期c.JSON()—— 返回JSON格式的响应
老师指出:学完前面的基础语法后,现在看框架代码已经能看懂很多了。
八、go mod 模块管理
老师简要介绍了 go mod —— Go的模块管理工具,类似于Java中的Maven。
8.1 什么是 go mod
go mod 是Go 1.11引入的模块管理系统,用于管理项目依赖。
老师提到:Go圣经(The Go Programming Language)这本书编写时还没有
go mod,所以书中没有相关内容。
8.2 常用命令
| 命令 | 说明 |
|---|---|
go mod init 模块名 |
初始化新项目,创建 go.mod 文件 |
go mod tidy |
自动拉取缺少的依赖,清理无用依赖 |
go mod download |
下载依赖到本地缓存 |
go mod vendor |
将依赖复制到项目vendor目录 |
go mod graph |
打印模块依赖图 |
go mod verify |
验证依赖完整性 |
8.3 go.mod 文件
v
module myproject
go 1.21
require (
github.com/gin-gonic/gin v1.9.1
)
九、本讲小结
| 知识点 | 要点 |
|---|---|
| 可变参数语法 | 参数名 ...类型 |
| 底层原理 | Go隐式创建数组,转为切片传入函数 |
| 位置约束 | 必须放在参数列表最后一个 |
| 遍历方式 | for range 遍历 |
...通用性 |
多种语言用 ... 表示可变 |
| Gin框架 | 高性能Go Web框架 |
| Context | Gin核心上下文对象 |
| go mod | Go模块管理,类似Maven |
| go mod init | 初始化项目模块 |
十、课后练习
- 编写可变参数函数
sum(nums ...int) int,返回所有参数的和 - 编写可变参数函数
max(nums ...int) int,返回最大值 - 编写函数
concat(prefix string, strs ...string),将prefix和所有字符串拼接 - 尝试将可变参数放在参数列表中间,观察编译错误
- 使用
for range遍历可变参数,打印每个值的下标和内容 - 运行
go mod init myproject创建一个新模块,观察生成的 go.mod 文件