💜 想真正擅长编程? 从一门课程开始,100% 免费

《笔记》第二十一篇 Go函数的可变参数

第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")
}

三、可变参数的底层原理

老师在课程中讲解了可变参数的底层机制:

在声明可变参数时,需要在参数列表的最后一个参数类型之前加上 ...,表示该函数会接收任意数量的该类型参数。

底层工作原理:

  1. Go会隐式地创建一个数组
  2. 将传入的参数复制到该数组中
  3. 把数组作为一个切片传递给函数
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 初始化项目模块

十、课后练习

  1. 编写可变参数函数 sum(nums ...int) int,返回所有参数的和
  2. 编写可变参数函数 max(nums ...int) int,返回最大值
  3. 编写函数 concat(prefix string, strs ...string),将prefix和所有字符串拼接
  4. 尝试将可变参数放在参数列表中间,观察编译错误
  5. 使用 for range 遍历可变参数,打印每个值的下标和内容
  6. 运行 go mod init myproject 创建一个新模块,观察生成的 go.mod 文件