Files
golang/golang-learning/03-functions/03-variadic-functions.go
2025-08-24 01:01:26 +08:00

757 lines
20 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
03-variadic-functions.go - Go 语言可变参数函数详解
学习目标:
1. 掌握可变参数函数的语法
2. 理解可变参数的传递机制
3. 学会可变参数的实际应用
4. 了解可变参数的限制和注意事项
5. 掌握可变参数的最佳实践
知识点:
- 可变参数语法 (...type)
- 可变参数的传递和展开
- 空参数和单参数处理
- 可变参数与切片的关系
- 可变参数的类型限制
- 实际应用场景
*/
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Println("=== Go 语言可变参数函数详解 ===\n")
// 演示基本可变参数函数
demonstrateBasicVariadicFunctions()
// 演示可变参数的传递
demonstrateVariadicParameterPassing()
// 演示可变参数与其他参数的组合
demonstrateVariadicWithOtherParams()
// 演示可变参数的类型处理
demonstrateVariadicTypeHandling()
// 演示可变参数的实际应用
demonstratePracticalApplications()
// 演示可变参数的高级用法
demonstrateAdvancedVariadicUsage()
// 演示可变参数的限制和注意事项
demonstrateVariadicLimitations()
}
// demonstrateBasicVariadicFunctions 演示基本可变参数函数
func demonstrateBasicVariadicFunctions() {
fmt.Println("1. 基本可变参数函数:")
// 数字求和
fmt.Printf(" 数字求和:\n")
fmt.Printf(" sum() = %d\n", sum())
fmt.Printf(" sum(1) = %d\n", sum(1))
fmt.Printf(" sum(1, 2, 3) = %d\n", sum(1, 2, 3))
fmt.Printf(" sum(1, 2, 3, 4, 5) = %d\n", sum(1, 2, 3, 4, 5))
// 字符串连接
fmt.Printf(" 字符串连接:\n")
fmt.Printf(" concat() = \"%s\"\n", concat())
fmt.Printf(" concat(\"Hello\") = \"%s\"\n", concat("Hello"))
fmt.Printf(" concat(\"Hello\", \" \", \"World\") = \"%s\"\n",
concat("Hello", " ", "World"))
fmt.Printf(" concat(\"Go\", \" is\", \" awesome\", \"!\") = \"%s\"\n",
concat("Go", " is", " awesome", "!"))
// 找最大值
fmt.Printf(" 找最大值:\n")
fmt.Printf(" max(1) = %d\n", max(1))
fmt.Printf(" max(3, 1, 4, 1, 5) = %d\n", max(3, 1, 4, 1, 5))
fmt.Printf(" max(10, 5, 8, 3, 9, 2, 7) = %d\n", max(10, 5, 8, 3, 9, 2, 7))
fmt.Println()
}
// demonstrateVariadicParameterPassing 演示可变参数的传递
func demonstrateVariadicParameterPassing() {
fmt.Println("2. 可变参数的传递:")
// 直接传递多个参数
fmt.Printf(" 直接传递多个参数:\n")
result1 := multiply(2, 3, 4, 5)
fmt.Printf(" multiply(2, 3, 4, 5) = %d\n", result1)
// 传递切片(需要展开)
fmt.Printf(" 传递切片(使用 ... 展开):\n")
numbers := []int{2, 3, 4, 5}
result2 := multiply(numbers...)
fmt.Printf(" numbers := %v\n", numbers)
fmt.Printf(" multiply(numbers...) = %d\n", result2)
// 混合传递
fmt.Printf(" 混合传递:\n")
result3 := multiply(1, 2)
moreNumbers := []int{3, 4, 5}
result4 := multiply(append([]int{1, 2}, moreNumbers...)...)
fmt.Printf(" multiply(1, 2) = %d\n", result3)
fmt.Printf(" 混合传递结果 = %d\n", result4)
// 空切片传递
fmt.Printf(" 空切片传递:\n")
var emptySlice []int
result5 := multiply(emptySlice...)
fmt.Printf(" multiply(emptySlice...) = %d\n", result5)
// 传递给其他可变参数函数
fmt.Printf(" 传递给其他可变参数函数:\n")
numbers2 := []int{10, 20, 30}
avg := average(numbers2...)
fmt.Printf(" average(%v) = %.2f\n", numbers2, avg)
fmt.Println()
}
// demonstrateVariadicWithOtherParams 演示可变参数与其他参数的组合
func demonstrateVariadicWithOtherParams() {
fmt.Println("3. 可变参数与其他参数的组合:")
// 固定参数 + 可变参数
fmt.Printf(" 固定参数 + 可变参数:\n")
result1 := formatMessage("INFO", "User login", "successful", "from IP 192.168.1.1")
fmt.Printf(" %s\n", result1)
result2 := formatMessage("ERROR", "Database connection failed")
fmt.Printf(" %s\n", result2)
// 多个固定参数 + 可变参数
fmt.Printf(" 多个固定参数 + 可变参数:\n")
result3 := calculateWithOperation("add", 1, 2, 3, 4, 5)
fmt.Printf(" calculateWithOperation(\"add\", 1, 2, 3, 4, 5) = %.2f\n", result3)
result4 := calculateWithOperation("multiply", 2, 3, 4)
fmt.Printf(" calculateWithOperation(\"multiply\", 2, 3, 4) = %.2f\n", result4)
result5 := calculateWithOperation("average", 10, 20, 30, 40, 50)
fmt.Printf(" calculateWithOperation(\"average\", 10, 20, 30, 40, 50) = %.2f\n", result5)
// 带默认值的可变参数函数
fmt.Printf(" 带默认值的可变参数函数:\n")
config1 := createConfig("myapp")
fmt.Printf(" createConfig(\"myapp\") = %+v\n", config1)
config2 := createConfig("myapp", "debug=true", "port=8080", "timeout=30")
fmt.Printf(" createConfig with options = %+v\n", config2)
fmt.Println()
}
// demonstrateVariadicTypeHandling 演示可变参数的类型处理
func demonstrateVariadicTypeHandling() {
fmt.Println("4. 可变参数的类型处理:")
// 不同类型的可变参数
fmt.Printf(" 字符串可变参数:\n")
joined := joinStrings(", ", "apple", "banana", "cherry", "date")
fmt.Printf(" joinStrings(\", \", \"apple\", \"banana\", \"cherry\", \"date\") = \"%s\"\n", joined)
// 接口类型的可变参数
fmt.Printf(" 接口类型的可变参数:\n")
printValues("混合类型:", 42, "hello", 3.14, true, []int{1, 2, 3})
// 结构体类型的可变参数
fmt.Printf(" 结构体类型的可变参数:\n")
person1 := Person{Name: "Alice", Age: 25}
person2 := Person{Name: "Bob", Age: 30}
person3 := Person{Name: "Charlie", Age: 35}
avgAge := calculateAverageAge(person1, person2, person3)
fmt.Printf(" 平均年龄: %.1f\n", avgAge)
// 函数类型的可变参数
fmt.Printf(" 函数类型的可变参数:\n")
add := func(a, b int) int { return a + b }
multiply := func(a, b int) int { return a * b }
subtract := func(a, b int) int { return a - b }
results := applyOperations(10, 5, add, multiply, subtract)
fmt.Printf(" applyOperations(10, 5, add, multiply, subtract) = %v\n", results)
fmt.Println()
}
// demonstratePracticalApplications 演示可变参数的实际应用
func demonstratePracticalApplications() {
fmt.Println("5. 可变参数的实际应用:")
// 应用1: 日志记录
fmt.Printf(" 应用1 - 日志记录:\n")
logInfo("用户登录", "用户ID", 123, "IP地址", "192.168.1.1")
logError("数据库连接失败", "错误码", 1001, "重试次数", 3)
logDebug("缓存命中", "键", "user:123", "值", "Alice")
// 应用2: SQL 查询构建
fmt.Printf(" 应用2 - SQL 查询构建:\n")
query1 := buildSelectQuery("users", "name", "email", "age")
fmt.Printf(" %s\n", query1)
query2 := buildSelectQuery("products", "id", "name", "price", "category", "stock")
fmt.Printf(" %s\n", query2)
// 应用3: HTTP 路由注册
fmt.Printf(" 应用3 - HTTP 路由注册:\n")
registerRoute("GET", "/users", authMiddleware, loggingMiddleware, getUsersHandler)
registerRoute("POST", "/users", authMiddleware, validateMiddleware, createUserHandler)
// 应用4: 数据验证
fmt.Printf(" 应用4 - 数据验证:\n")
userData := map[string]interface{}{
"name": "Alice",
"email": "alice@example.com",
"age": 25,
}
errors := validateData(userData,
validateRequired("name"),
validateEmail("email"),
validateRange("age", 0, 150),
)
if len(errors) == 0 {
fmt.Printf(" 数据验证通过\n")
} else {
fmt.Printf(" 验证错误: %v\n", errors)
}
// 应用5: 配置合并
fmt.Printf(" 应用5 - 配置合并:\n")
defaultConfig := Config{Port: 8080, Debug: false, Timeout: 30}
userConfig := Config{Debug: true, MaxConnections: 100}
envConfig := Config{Port: 9090, Timeout: 60}
finalConfig := mergeConfigs(defaultConfig, userConfig, envConfig)
fmt.Printf(" 最终配置: %+v\n", finalConfig)
fmt.Println()
}
// demonstrateAdvancedVariadicUsage 演示可变参数的高级用法
func demonstrateAdvancedVariadicUsage() {
fmt.Println("6. 可变参数的高级用法:")
// 可变参数的递归处理
fmt.Printf(" 可变参数的递归处理:\n")
result1 := recursiveSum(1, 2, 3, 4, 5)
fmt.Printf(" recursiveSum(1, 2, 3, 4, 5) = %d\n", result1)
// 可变参数的函数式处理
fmt.Printf(" 可变参数的函数式处理:\n")
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
evenSum := reduceInts(filterInts(numbers, isEven)...)
fmt.Printf(" 偶数之和: %d\n", evenSum)
oddProduct := reduceInts(filterInts(numbers, isOdd)...)
fmt.Printf(" 奇数之和: %d\n", oddProduct)
// 可变参数的管道处理
fmt.Printf(" 可变参数的管道处理:\n")
pipeline := createPipeline(
func(x int) int { return x * 2 }, // 乘以2
func(x int) int { return x + 1 }, // 加1
func(x int) int { return x * x }, // 平方
)
for i := 1; i <= 3; i++ {
result := pipeline(i)
fmt.Printf(" pipeline(%d) = %d\n", i, result)
}
// 可变参数的选项模式
fmt.Printf(" 可变参数的选项模式:\n")
server1 := createServer("localhost",
withPort(8080),
withTimeout(30),
withDebug(true),
)
fmt.Printf(" 服务器1: %+v\n", server1)
server2 := createServer("0.0.0.0",
withPort(9090),
withMaxConnections(1000),
)
fmt.Printf(" 服务器2: %+v\n", server2)
fmt.Println()
}
// demonstrateVariadicLimitations 演示可变参数的限制和注意事项
func demonstrateVariadicLimitations() {
fmt.Println("7. 可变参数的限制和注意事项:")
// 限制1: 可变参数必须是最后一个参数
fmt.Printf(" 限制1: 可变参数必须是最后一个参数\n")
fmt.Printf(" ✓ func example(a int, b ...string) - 正确\n")
fmt.Printf(" ✗ func example(a ...int, b string) - 错误\n")
// 限制2: 一个函数只能有一个可变参数
fmt.Printf(" 限制2: 一个函数只能有一个可变参数\n")
fmt.Printf(" ✗ func example(a ...int, b ...string) - 错误\n")
// 注意事项1: 可变参数是切片
fmt.Printf(" 注意事项1: 可变参数在函数内部是切片\n")
inspectVariadicParam(1, 2, 3, 4, 5)
// 注意事项2: 修改可变参数会影响原始切片
fmt.Printf(" 注意事项2: 修改可变参数可能影响原始数据\n")
originalSlice := []int{1, 2, 3, 4, 5}
fmt.Printf(" 修改前: %v\n", originalSlice)
modifyVariadicParam(originalSlice...)
fmt.Printf(" 修改后: %v\n", originalSlice)
// 注意事项3: 性能考虑
fmt.Printf(" 注意事项3: 性能考虑\n")
fmt.Printf(" - 传递大量参数时,切片展开可能有性能开销\n")
fmt.Printf(" - 考虑直接传递切片而不是可变参数\n")
// 注意事项4: 类型安全
fmt.Printf(" 注意事项4: 类型安全\n")
fmt.Printf(" - 可变参数必须是相同类型\n")
fmt.Printf(" - 使用 interface{} 可以接受不同类型,但失去类型安全\n")
// 最佳实践
fmt.Printf(" 最佳实践:\n")
fmt.Printf(" 1. 优先考虑切片参数而不是可变参数\n")
fmt.Printf(" 2. 可变参数适用于调用时参数数量不确定的场景\n")
fmt.Printf(" 3. 注意可变参数的性能影响\n")
fmt.Printf(" 4. 使用选项模式处理复杂的可选参数\n")
fmt.Println()
}
// ========== 函数定义 ==========
// 基本可变参数函数
func sum(numbers ...int) int {
total := 0
for _, num := range numbers {
total += num
}
return total
}
func concat(strings ...string) string {
result := ""
for _, str := range strings {
result += str
}
return result
}
func max(numbers ...int) int {
if len(numbers) == 0 {
return 0
}
maximum := numbers[0]
for _, num := range numbers {
if num > maximum {
maximum = num
}
}
return maximum
}
func multiply(numbers ...int) int {
if len(numbers) == 0 {
return 0
}
result := 1
for _, num := range numbers {
result *= num
}
return result
}
func average(numbers ...int) float64 {
if len(numbers) == 0 {
return 0
}
total := sum(numbers...)
return float64(total) / float64(len(numbers))
}
// 固定参数 + 可变参数
func formatMessage(level string, messages ...string) string {
timestamp := "2024-01-01 12:00:00"
allMessages := strings.Join(messages, " ")
return fmt.Sprintf("[%s] %s: %s", timestamp, level, allMessages)
}
func calculateWithOperation(operation string, numbers ...int) float64 {
if len(numbers) == 0 {
return 0
}
switch operation {
case "add":
return float64(sum(numbers...))
case "multiply":
return float64(multiply(numbers...))
case "average":
return average(numbers...)
default:
return 0
}
}
type AppConfig struct {
Name string
Options map[string]string
}
func createConfig(name string, options ...string) AppConfig {
config := AppConfig{
Name: name,
Options: make(map[string]string),
}
for _, option := range options {
parts := strings.SplitN(option, "=", 2)
if len(parts) == 2 {
config.Options[parts[0]] = parts[1]
}
}
return config
}
// 类型处理函数
func joinStrings(separator string, strings ...string) string {
return strings.Join(strings, separator)
}
func printValues(prefix string, values ...interface{}) {
fmt.Printf(" %s ", prefix)
for i, value := range values {
if i > 0 {
fmt.Printf(", ")
}
fmt.Printf("%v", value)
}
fmt.Printf("\n")
}
type Person struct {
Name string
Age int
}
func calculateAverageAge(people ...Person) float64 {
if len(people) == 0 {
return 0
}
totalAge := 0
for _, person := range people {
totalAge += person.Age
}
return float64(totalAge) / float64(len(people))
}
func applyOperations(a, b int, operations ...func(int, int) int) []int {
results := make([]int, len(operations))
for i, op := range operations {
results[i] = op(a, b)
}
return results
}
// 实际应用函数
func logInfo(message string, keyValues ...interface{}) {
fmt.Printf(" [INFO] %s", message)
for i := 0; i < len(keyValues); i += 2 {
if i+1 < len(keyValues) {
fmt.Printf(" %v=%v", keyValues[i], keyValues[i+1])
}
}
fmt.Printf("\n")
}
func logError(message string, keyValues ...interface{}) {
fmt.Printf(" [ERROR] %s", message)
for i := 0; i < len(keyValues); i += 2 {
if i+1 < len(keyValues) {
fmt.Printf(" %v=%v", keyValues[i], keyValues[i+1])
}
}
fmt.Printf("\n")
}
func logDebug(message string, keyValues ...interface{}) {
fmt.Printf(" [DEBUG] %s", message)
for i := 0; i < len(keyValues); i += 2 {
if i+1 < len(keyValues) {
fmt.Printf(" %v=%v", keyValues[i], keyValues[i+1])
}
}
fmt.Printf("\n")
}
func buildSelectQuery(table string, columns ...string) string {
if len(columns) == 0 {
return fmt.Sprintf("SELECT * FROM %s", table)
}
return fmt.Sprintf("SELECT %s FROM %s", strings.Join(columns, ", "), table)
}
// 模拟中间件和处理器
func authMiddleware() { fmt.Printf(" - 认证中间件\n") }
func loggingMiddleware() { fmt.Printf(" - 日志中间件\n") }
func validateMiddleware() { fmt.Printf(" - 验证中间件\n") }
func getUsersHandler() { fmt.Printf(" - 获取用户处理器\n") }
func createUserHandler() { fmt.Printf(" - 创建用户处理器\n") }
func registerRoute(method, path string, handlers ...func()) {
fmt.Printf(" 注册路由: %s %s\n", method, path)
for _, handler := range handlers {
handler()
}
}
// 验证函数类型
type ValidationFunc func(map[string]interface{}) []string
func validateRequired(field string) ValidationFunc {
return func(data map[string]interface{}) []string {
if _, exists := data[field]; !exists {
return []string{fmt.Sprintf("字段 %s 是必需的", field)}
}
return nil
}
}
func validateEmail(field string) ValidationFunc {
return func(data map[string]interface{}) []string {
if email, ok := data[field].(string); ok {
if !strings.Contains(email, "@") {
return []string{fmt.Sprintf("字段 %s 不是有效的邮箱", field)}
}
}
return nil
}
}
func validateRange(field string, min, max int) ValidationFunc {
return func(data map[string]interface{}) []string {
if value, ok := data[field].(int); ok {
if value < min || value > max {
return []string{fmt.Sprintf("字段 %s 必须在 %d-%d 范围内", field, min, max)}
}
}
return nil
}
}
func validateData(data map[string]interface{}, validators ...ValidationFunc) []string {
var allErrors []string
for _, validator := range validators {
if errors := validator(data); errors != nil {
allErrors = append(allErrors, errors...)
}
}
return allErrors
}
// 配置合并
type Config struct {
Port int
Debug bool
Timeout int
MaxConnections int
}
func mergeConfigs(configs ...Config) Config {
result := Config{}
for _, config := range configs {
if config.Port != 0 {
result.Port = config.Port
}
if config.Debug {
result.Debug = config.Debug
}
if config.Timeout != 0 {
result.Timeout = config.Timeout
}
if config.MaxConnections != 0 {
result.MaxConnections = config.MaxConnections
}
}
return result
}
// 高级用法函数
func recursiveSum(numbers ...int) int {
if len(numbers) == 0 {
return 0
}
if len(numbers) == 1 {
return numbers[0]
}
return numbers[0] + recursiveSum(numbers[1:]...)
}
func filterInts(numbers []int, predicate func(int) bool) []int {
var result []int
for _, num := range numbers {
if predicate(num) {
result = append(result, num)
}
}
return result
}
func reduceInts(numbers ...int) int {
return sum(numbers...)
}
func isEven(n int) bool { return n%2 == 0 }
func isOdd(n int) bool { return n%2 == 1 }
func createPipeline(functions ...func(int) int) func(int) int {
return func(input int) int {
result := input
for _, fn := range functions {
result = fn(result)
}
return result
}
}
// 选项模式
type Server struct {
Host string
Port int
Timeout int
Debug bool
MaxConnections int
}
type ServerOption func(*Server)
func withPort(port int) ServerOption {
return func(s *Server) {
s.Port = port
}
}
func withTimeout(timeout int) ServerOption {
return func(s *Server) {
s.Timeout = timeout
}
}
func withDebug(debug bool) ServerOption {
return func(s *Server) {
s.Debug = debug
}
}
func withMaxConnections(max int) ServerOption {
return func(s *Server) {
s.MaxConnections = max
}
}
func createServer(host string, options ...ServerOption) Server {
server := Server{
Host: host,
Port: 80,
Timeout: 10,
Debug: false,
}
for _, option := range options {
option(&server)
}
return server
}
// 限制和注意事项函数
func inspectVariadicParam(numbers ...int) {
fmt.Printf(" 可变参数类型: %T\n", numbers)
fmt.Printf(" 可变参数长度: %d\n", len(numbers))
fmt.Printf(" 可变参数容量: %d\n", cap(numbers))
fmt.Printf(" 可变参数值: %v\n", numbers)
}
func modifyVariadicParam(numbers ...int) {
if len(numbers) > 0 {
numbers[0] = 999 // 修改第一个元素
}
}
/*
运行这个程序:
go run 03-variadic-functions.go
学习要点:
1. 可变参数使用 ...type 语法,必须是函数的最后一个参数
2. 可变参数在函数内部是切片类型
3. 传递切片给可变参数函数需要使用 ... 展开操作符
4. 一个函数只能有一个可变参数
5. 可变参数提供了灵活的函数调用方式
可变参数的语法:
- 定义: func name(params ...type) { ... }
- 调用: name(arg1, arg2, arg3) 或 name(slice...)
- 内部: params 是 []type 类型的切片
常见应用场景:
1. 数学运算函数(求和、求积等)
2. 字符串处理函数
3. 日志记录函数
4. 配置和选项处理
5. 中间件和处理器链
6. 数据验证
7. SQL 查询构建
最佳实践:
1. 优先考虑切片参数,可变参数适用于调用便利性
2. 使用选项模式处理复杂的可选参数
3. 注意可变参数的性能影响
4. 保持函数签名的简洁性
5. 合理使用接口类型的可变参数
限制和注意事项:
1. 可变参数必须是最后一个参数
2. 一个函数只能有一个可变参数
3. 可变参数是切片,修改会影响原始数据
4. 大量参数时考虑性能影响
5. 类型必须相同(除非使用 interface{}
高级用法:
1. 函数式编程风格
2. 选项模式
3. 中间件模式
4. 管道处理
5. 递归处理
6. 配置合并
性能考虑:
1. 切片展开有一定开销
2. 大量参数时考虑直接传递切片
3. 避免在热点代码中过度使用
4. 考虑内存分配的影响
*/