/* 02-multiple-returns.go - Go 语言多返回值详解 学习目标: 1. 掌握多返回值的语法和用法 2. 理解命名返回值的优势 3. 学会错误处理的惯用模式 4. 了解多返回值的实际应用场景 5. 掌握返回值的最佳实践 知识点: - 多返回值语法 - 命名返回值 - 错误处理模式 - 返回值解构 - 忽略返回值 - 多返回值的性能考虑 - 实际应用场景 */ package main import ( "errors" "fmt" "math" "strconv" "strings" "time" ) func main() { fmt.Println("=== Go 语言多返回值详解 ===\n") // 演示基本多返回值 demonstrateBasicMultipleReturns() // 演示命名返回值 demonstrateNamedReturns() // 演示错误处理模式 demonstrateErrorHandling() // 演示返回值解构和忽略 demonstrateReturnValueHandling() // 演示多返回值的实际应用 demonstratePracticalApplications() // 演示多返回值的高级用法 demonstrateAdvancedUsage() // 演示性能考虑 demonstratePerformanceConsiderations() } // demonstrateBasicMultipleReturns 演示基本多返回值 func demonstrateBasicMultipleReturns() { fmt.Println("1. 基本多返回值:") // 两个返回值 fmt.Printf(" 两个返回值:\n") quotient, remainder := divmod(17, 5) fmt.Printf(" 17 ÷ 5 = %d 余 %d\n", quotient, remainder) // 三个返回值 fmt.Printf(" 三个返回值:\n") min, max, avg := analyzeNumbers([]int{3, 7, 1, 9, 4, 6}) fmt.Printf(" 数组 [3, 7, 1, 9, 4, 6] - 最小值: %d, 最大值: %d, 平均值: %.2f\n", min, max, avg) // 不同类型的返回值 fmt.Printf(" 不同类型的返回值:\n") name, age, height, isStudent := getPersonInfo() fmt.Printf(" 个人信息 - 姓名: %s, 年龄: %d, 身高: %.1fcm, 学生: %t\n", name, age, height, isStudent) // 返回值和错误 fmt.Printf(" 返回值和错误:\n") result, err := safeDivide(10, 2) if err != nil { fmt.Printf(" 错误: %v\n", err) } else { fmt.Printf(" 10 ÷ 2 = %.2f\n", result) } result, err = safeDivide(10, 0) if err != nil { fmt.Printf(" 错误: %v\n", err) } else { fmt.Printf(" 10 ÷ 0 = %.2f\n", result) } fmt.Println() } // demonstrateNamedReturns 演示命名返回值 func demonstrateNamedReturns() { fmt.Println("2. 命名返回值:") // 基本命名返回值 fmt.Printf(" 基本命名返回值:\n") area, perimeter := calculateRectangle(5, 3) fmt.Printf(" 矩形 5×3 - 面积: %d, 周长: %d\n", area, perimeter) // 命名返回值的提前返回 fmt.Printf(" 命名返回值的提前返回:\n") score, grade, pass := evaluateScore(85) fmt.Printf(" 分数 85 - 等级: %s, 是否及格: %t\n", grade, pass) score, grade, pass = evaluateScore(45) fmt.Printf(" 分数 45 - 等级: %s, 是否及格: %t\n", grade, pass) // 复杂的命名返回值 fmt.Printf(" 复杂的命名返回值:\n") valid, reason, suggestions := validatePassword("123") fmt.Printf(" 密码 \"123\" - 有效: %t, 原因: %s\n", valid, reason) if len(suggestions) > 0 { fmt.Printf(" 建议: %v\n", suggestions) } valid, reason, suggestions = validatePassword("SecurePass123!") fmt.Printf(" 密码 \"SecurePass123!\" - 有效: %t, 原因: %s\n", valid, reason) fmt.Println() } // demonstrateErrorHandling 演示错误处理模式 func demonstrateErrorHandling() { fmt.Println("3. 错误处理模式:") // 标准错误处理模式 fmt.Printf(" 标准错误处理模式:\n") // 字符串转整数 value, err := parseInteger("123") if err != nil { fmt.Printf(" 解析错误: %v\n", err) } else { fmt.Printf(" 解析成功: %d\n", value) } value, err = parseInteger("abc") if err != nil { fmt.Printf(" 解析错误: %v\n", err) } else { fmt.Printf(" 解析成功: %d\n", value) } // 文件操作模拟 fmt.Printf(" 文件操作模拟:\n") content, err := readFile("config.txt") if err != nil { fmt.Printf(" 读取文件错误: %v\n", err) } else { fmt.Printf(" 文件内容: %s\n", content) } // 网络请求模拟 fmt.Printf(" 网络请求模拟:\n") data, statusCode, err := httpGet("https://api.example.com/users") if err != nil { fmt.Printf(" 请求错误: %v\n", err) } else { fmt.Printf(" 状态码: %d, 数据长度: %d\n", statusCode, len(data)) } // 多层错误处理 fmt.Printf(" 多层错误处理:\n") result, err := processUserData("user123") if err != nil { fmt.Printf(" 处理用户数据错误: %v\n", err) } else { fmt.Printf(" 处理结果: %s\n", result) } fmt.Println() } // demonstrateReturnValueHandling 演示返回值解构和忽略 func demonstrateReturnValueHandling() { fmt.Println("4. 返回值解构和忽略:") // 接收所有返回值 fmt.Printf(" 接收所有返回值:\n") x, y, z := getCoordinates() fmt.Printf(" 坐标: (%d, %d, %d)\n", x, y, z) // 忽略某些返回值 fmt.Printf(" 忽略某些返回值:\n") _, _, avgZ := getCoordinates() fmt.Printf(" 只关心 Z 坐标: %d\n", avgZ) // 只检查错误 fmt.Printf(" 只检查错误:\n") _, err := safeDivide(10, 2) if err != nil { fmt.Printf(" 操作失败: %v\n", err) } else { fmt.Printf(" 操作成功\n") } // 链式调用 fmt.Printf(" 链式调用:\n") result, err := processChain("input") if err != nil { fmt.Printf(" 链式处理错误: %v\n", err) } else { fmt.Printf(" 链式处理结果: %s\n", result) } // 多重赋值 fmt.Printf(" 多重赋值:\n") a, b := 10, 20 fmt.Printf(" 交换前: a=%d, b=%d\n", a, b) a, b = swap(a, b) fmt.Printf(" 交换后: a=%d, b=%d\n", a, b) fmt.Println() } // demonstratePracticalApplications 演示多返回值的实际应用 func demonstratePracticalApplications() { fmt.Println("5. 多返回值的实际应用:") // 应用1: 数据库查询模拟 fmt.Printf(" 应用1 - 数据库查询模拟:\n") user, found, err := findUserByID(123) if err != nil { fmt.Printf(" 查询错误: %v\n", err) } else if !found { fmt.Printf(" 用户不存在\n") } else { fmt.Printf(" 找到用户: %+v\n", user) } // 应用2: 缓存操作 fmt.Printf(" 应用2 - 缓存操作:\n") value, hit, err := getFromCache("user:123") if err != nil { fmt.Printf(" 缓存错误: %v\n", err) } else if hit { fmt.Printf(" 缓存命中: %s\n", value) } else { fmt.Printf(" 缓存未命中\n") } // 应用3: 配置解析 fmt.Printf(" 应用3 - 配置解析:\n") config, warnings, err := parseConfig("app.conf") if err != nil { fmt.Printf(" 配置解析错误: %v\n", err) } else { fmt.Printf(" 配置加载成功: %+v\n", config) if len(warnings) > 0 { fmt.Printf(" 警告: %v\n", warnings) } } // 应用4: 数据验证 fmt.Printf(" 应用4 - 数据验证:\n") userData := map[string]string{ "name": "Alice", "email": "alice@example.com", "age": "25", } valid, errors := validateUserData(userData) fmt.Printf(" 用户数据验证 - 有效: %t\n", valid) if len(errors) > 0 { fmt.Printf(" 验证错误: %v\n", errors) } // 应用5: 统计分析 fmt.Printf(" 应用5 - 统计分析:\n") data := []float64{1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0} mean, median, stddev := calculateStatistics(data) fmt.Printf(" 数据: %v\n", data) fmt.Printf(" 统计结果 - 平均值: %.2f, 中位数: %.2f, 标准差: %.2f\n", mean, median, stddev) fmt.Println() } // demonstrateAdvancedUsage 演示多返回值的高级用法 func demonstrateAdvancedUsage() { fmt.Println("6. 多返回值的高级用法:") // 返回函数 fmt.Printf(" 返回函数:\n") add, multiply := getMathOperations() fmt.Printf(" add(5, 3) = %d\n", add(5, 3)) fmt.Printf(" multiply(5, 3) = %d\n", multiply(5, 3)) // 返回接口 fmt.Printf(" 返回接口:\n") reader, writer := getIOOperations() data := []byte("Hello, World!") n, err := writer.Write(data) if err != nil { fmt.Printf(" 写入错误: %v\n", err) } else { fmt.Printf(" 写入 %d 字节\n", n) } buffer := make([]byte, 13) n, err = reader.Read(buffer) if err != nil { fmt.Printf(" 读取错误: %v\n", err) } else { fmt.Printf(" 读取 %d 字节: %s\n", n, string(buffer[:n])) } // 返回通道 fmt.Printf(" 返回通道:\n") input, output := createPipeline() // 发送数据 go func() { for i := 1; i <= 3; i++ { input <- i } close(input) }() // 接收处理后的数据 for result := range output { fmt.Printf(" 处理结果: %d\n", result) } fmt.Println() } // demonstratePerformanceConsiderations 演示性能考虑 func demonstratePerformanceConsiderations() { fmt.Println("7. 性能考虑:") // 返回值的内存分配 fmt.Printf(" 返回值的内存分配:\n") // 返回值拷贝 vs 返回指针 largeData := make([]int, 1000) for i := range largeData { largeData[i] = i } // 返回拷贝(可能影响性能) copied, size := copyLargeData(largeData) fmt.Printf(" 返回拷贝 - 大小: %d, 第一个元素: %d\n", size, copied[0]) // 返回指针(更高效) ptr, size := referenceLargeData(largeData) fmt.Printf(" 返回指针 - 大小: %d, 第一个元素: %d\n", size, (*ptr)[0]) // 多返回值 vs 结构体 fmt.Printf(" 多返回值 vs 结构体:\n") // 使用多返回值 name, age, email := getUserInfo1() fmt.Printf(" 多返回值: %s, %d, %s\n", name, age, email) // 使用结构体 user := getUserInfo2() fmt.Printf(" 结构体: %s, %d, %s\n", user.Name, user.Age, user.Email) // 错误处理的性能 fmt.Printf(" 错误处理的性能:\n") // 正常情况 start := time.Now() for i := 0; i < 1000; i++ { _, err := fastOperation(i) if err != nil { // 处理错误 } } duration := time.Since(start) fmt.Printf(" 1000次正常操作耗时: %v\n", duration) fmt.Println() } // ========== 函数定义 ========== // 基本多返回值函数 func divmod(a, b int) (int, int) { return a / b, a % b } func analyzeNumbers(numbers []int) (int, int, float64) { if len(numbers) == 0 { return 0, 0, 0 } min, max := numbers[0], numbers[0] sum := 0 for _, num := range numbers { if num < min { min = num } if num > max { max = num } sum += num } avg := float64(sum) / float64(len(numbers)) return min, max, avg } func getPersonInfo() (string, int, float64, bool) { return "Alice", 25, 165.5, true } func safeDivide(a, b float64) (float64, error) { if b == 0 { return 0, errors.New("除数不能为零") } return a / b, nil } // 命名返回值函数 func calculateRectangle(width, height int) (area, perimeter int) { area = width * height perimeter = 2 * (width + height) return // 自动返回命名的返回值 } func evaluateScore(score int) (originalScore int, grade string, pass bool) { originalScore = score if score < 0 || score > 100 { grade = "无效" return // 提前返回 } switch { case score >= 90: grade = "A" case score >= 80: grade = "B" case score >= 70: grade = "C" case score >= 60: grade = "D" default: grade = "F" } pass = score >= 60 return } func validatePassword(password string) (valid bool, reason string, suggestions []string) { if len(password) < 8 { reason = "密码长度不足8位" suggestions = append(suggestions, "增加密码长度") return } hasUpper := strings.ContainsAny(password, "ABCDEFGHIJKLMNOPQRSTUVWXYZ") hasLower := strings.ContainsAny(password, "abcdefghijklmnopqrstuvwxyz") hasDigit := strings.ContainsAny(password, "0123456789") hasSpecial := strings.ContainsAny(password, "!@#$%^&*") if !hasUpper { suggestions = append(suggestions, "添加大写字母") } if !hasLower { suggestions = append(suggestions, "添加小写字母") } if !hasDigit { suggestions = append(suggestions, "添加数字") } if !hasSpecial { suggestions = append(suggestions, "添加特殊字符") } if hasUpper && hasLower && hasDigit && hasSpecial { valid = true reason = "密码强度良好" } else { reason = "密码强度不足" } return } // 错误处理函数 func parseInteger(s string) (int, error) { value, err := strconv.Atoi(s) if err != nil { return 0, fmt.Errorf("无法解析整数 '%s': %w", s, err) } return value, nil } func readFile(filename string) (string, error) { // 模拟文件读取 if filename == "config.txt" { return "server_port=8080\ndebug=true", nil } return "", fmt.Errorf("文件 '%s' 不存在", filename) } func httpGet(url string) ([]byte, int, error) { // 模拟HTTP请求 if strings.Contains(url, "example.com") { return []byte(`{"users": [{"id": 1, "name": "Alice"}]}`), 200, nil } return nil, 0, errors.New("网络连接失败") } func processUserData(userID string) (string, error) { // 模拟多层处理 if userID == "" { return "", errors.New("用户ID不能为空") } // 模拟数据库查询 if userID == "user123" { return "用户数据处理完成", nil } return "", fmt.Errorf("用户 '%s' 不存在", userID) } // 返回值处理函数 func getCoordinates() (int, int, int) { return 10, 20, 30 } func processChain(input string) (string, error) { if input == "" { return "", errors.New("输入不能为空") } // 模拟处理链 step1 := strings.ToUpper(input) step2 := step1 + "_PROCESSED" return step2, nil } func swap(a, b int) (int, int) { return b, a } // 实际应用函数 type User struct { ID int Name string Email string } func findUserByID(id int) (User, bool, error) { // 模拟数据库查询 if id <= 0 { return User{}, false, errors.New("无效的用户ID") } if id == 123 { return User{ID: 123, Name: "Alice", Email: "alice@example.com"}, true, nil } return User{}, false, nil } func getFromCache(key string) (string, bool, error) { // 模拟缓存操作 cache := map[string]string{ "user:123": "Alice", "user:456": "Bob", } if value, exists := cache[key]; exists { return value, true, nil } return "", false, nil } type Config struct { Port int Debug bool Timeout int } func parseConfig(filename string) (Config, []string, error) { // 模拟配置解析 config := Config{Port: 8080, Debug: true, Timeout: 30} warnings := []string{"使用默认超时值"} if filename == "app.conf" { return config, warnings, nil } return Config{}, nil, fmt.Errorf("配置文件 '%s' 不存在", filename) } func validateUserData(data map[string]string) (bool, []string) { var errors []string if name := data["name"]; name == "" { errors = append(errors, "姓名不能为空") } if email := data["email"]; !strings.Contains(email, "@") { errors = append(errors, "邮箱格式无效") } if ageStr := data["age"]; ageStr != "" { if age, err := strconv.Atoi(ageStr); err != nil || age < 0 || age > 150 { errors = append(errors, "年龄无效") } } return len(errors) == 0, errors } func calculateStatistics(data []float64) (mean, median, stddev float64) { if len(data) == 0 { return 0, 0, 0 } // 计算平均值 sum := 0.0 for _, v := range data { sum += v } mean = sum / float64(len(data)) // 计算中位数(简化版) median = data[len(data)/2] // 计算标准差 variance := 0.0 for _, v := range data { variance += (v - mean) * (v - mean) } stddev = math.Sqrt(variance / float64(len(data))) return } // 高级用法函数 func getMathOperations() (func(int, int) int, func(int, int) int) { add := func(a, b int) int { return a + b } multiply := func(a, b int) int { return a * b } return add, multiply } type MockReader struct { data []byte pos int } func (r *MockReader) Read(p []byte) (n int, error) { if r.pos >= len(r.data) { return 0, errors.New("EOF") } n = copy(p, r.data[r.pos:]) r.pos += n return n, nil } type MockWriter struct { data []byte } func (w *MockWriter) Write(p []byte) (n int, error) { w.data = append(w.data, p...) return len(p), nil } func getIOOperations() (*MockReader, *MockWriter) { reader := &MockReader{data: []byte("Hello, World!")} writer := &MockWriter{} return reader, writer } func createPipeline() (chan<- int, <-chan int) { input := make(chan int) output := make(chan int) go func() { defer close(output) for value := range input { output <- value * 2 // 处理数据 } }() return input, output } // 性能考虑函数 func copyLargeData(data []int) ([]int, int) { copied := make([]int, len(data)) copy(copied, data) return copied, len(copied) } func referenceLargeData(data []int) (*[]int, int) { return &data, len(data) } func getUserInfo1() (string, int, string) { return "Alice", 25, "alice@example.com" } type UserInfo struct { Name string Age int Email string } func getUserInfo2() UserInfo { return UserInfo{Name: "Alice", Age: 25, Email: "alice@example.com"} } func fastOperation(n int) (int, error) { if n < 0 { return 0, errors.New("负数") } return n * 2, nil } /* 运行这个程序: go run 02-multiple-returns.go 学习要点: 1. Go 支持多返回值,这是其独特且强大的特性 2. 多返回值常用于返回结果和错误信息 3. 命名返回值可以提高代码可读性,支持提前返回 4. 可以使用 _ 忽略不需要的返回值 5. 多返回值是 Go 错误处理的基础 多返回值的优势: 1. 避免使用指针参数传递多个结果 2. 使错误处理更加明确和一致 3. 提高代码的可读性和维护性 4. 支持函数式编程风格 常见模式: 1. (result, error) - 标准错误处理模式 2. (value, ok) - 检查操作是否成功 3. (value, found, error) - 查询操作模式 4. 命名返回值 - 提高可读性 最佳实践: 1. 错误通常作为最后一个返回值 2. 使用命名返回值提高复杂函数的可读性 3. 适当使用 _ 忽略不需要的返回值 4. 保持返回值数量合理(通常不超过3-4个) 5. 考虑使用结构体替代过多的返回值 性能考虑: 1. 多返回值通常比传递指针参数更高效 2. 大对象考虑返回指针而不是值拷贝 3. 命名返回值可能有轻微的性能开销 4. 错误处理的性能影响通常可以忽略 应用场景: 1. 错误处理 2. 数据库查询 3. 网络操作 4. 文件操作 5. 数据验证 6. 统计计算 7. 缓存操作 */