多返回值 #

一、多返回值概述 #

Go语言支持函数返回多个值,这是Go的特色功能之一。

二、基本用法 #

2.1 定义多返回值 #

go
func divmod(a, b int) (int, int) {
    return a / b, a % b
}

2.2 接收多返回值 #

go
quotient, remainder := divmod(10, 3)
fmt.Println(quotient, remainder)  // 3 1

2.3 忽略部分返回值 #

go
quotient, _ := divmod(10, 3)
fmt.Println(quotient)  // 3

三、命名返回值 #

3.1 基本语法 #

go
func divmod(a, b int) (quotient, remainder int) {
    quotient = a / b
    remainder = a % b
    return
}

3.2 自动初始化 #

命名返回值自动初始化为零值:

go
func counter() (count int) {
    fmt.Println(count)  // 0
    count = 10
    return
}

3.3 裸返回 #

命名返回值可以使用裸返回:

go
func divmod(a, b int) (quotient, remainder int) {
    quotient = a / b
    remainder = a % b
    return  // 自动返回命名变量
}

3.4 覆盖返回值 #

可以在return时覆盖:

go
func divmod(a, b int) (quotient, remainder int) {
    quotient = a / b
    remainder = a % b
    return quotient * 2, remainder * 2  // 覆盖
}

四、常见模式 #

4.1 值与错误 #

go
func readFile(path string) ([]byte, error) {
    data, err := os.ReadFile(path)
    if err != nil {
        return nil, err
    }
    return data, nil
}

4.2 值与状态 #

go
func findUser(id int) (User, bool) {
    for _, u := range users {
        if u.ID == id {
            return u, true
        }
    }
    return User{}, false
}

user, found := findUser(1)
if found {
    fmt.Println(user)
}

4.3 多个值 #

go
func minmax(numbers []int) (min, max int) {
    if len(numbers) == 0 {
        return 0, 0
    }
    min, max = numbers[0], numbers[0]
    for _, n := range numbers {
        if n < min {
            min = n
        }
        if n > max {
            max = n
        }
    }
    return
}

4.4 解析函数 #

go
func parsePoint(s string) (x, y int, err error) {
    parts := strings.Split(s, ",")
    if len(parts) != 2 {
        return 0, 0, errors.New("invalid format")
    }
    
    x, err = strconv.Atoi(parts[0])
    if err != nil {
        return 0, 0, err
    }
    
    y, err = strconv.Atoi(parts[1])
    if err != nil {
        return 0, 0, err
    }
    
    return x, y, nil
}

五、实际应用 #

5.1 文件操作 #

go
func readLines(path string) (lines []string, err error) {
    file, err := os.Open(path)
    if err != nil {
        return
    }
    defer file.Close()
    
    scanner := bufio.NewScanner(file)
    for scanner.Scan() {
        lines = append(lines, scanner.Text())
    }
    
    err = scanner.Err()
    return
}

5.2 HTTP处理 #

go
func handleRequest(r *http.Request) (status int, body []byte, err error) {
    if r.Method != "GET" {
        return http.StatusMethodNotAllowed, nil, nil
    }
    
    data, err := fetchData(r.URL.Query().Get("id"))
    if err != nil {
        return http.StatusInternalServerError, nil, err
    }
    
    body, err = json.Marshal(data)
    if err != nil {
        return http.StatusInternalServerError, nil, err
    }
    
    return http.StatusOK, body, nil
}

5.3 数据库操作 #

go
func queryUser(db *sql.DB, id int) (user User, err error) {
    row := db.QueryRow("SELECT id, name, email FROM users WHERE id = ?", id)
    err = row.Scan(&user.ID, &user.Name, &user.Email)
    return
}

5.4 缓存模式 #

go
func getWithCache(key string) (value string, cached bool, err error) {
    if v, ok := cache.Get(key); ok {
        return v, true, nil
    }
    
    v, err := fetchFromDB(key)
    if err != nil {
        return "", false, err
    }
    
    cache.Set(key, v)
    return v, false, nil
}

六、命名返回值注意事项 #

6.1 变量遮蔽 #

go
func example() (result int) {
    result = 10
    if true {
        result := 20  // 新变量,遮蔽命名返回值
        fmt.Println(result)  // 20
    }
    return  // 返回10
}

6.2 裸返回可读性 #

go
// 不推荐:长函数中使用裸返回
func process(data []int) (result int, err error) {
    // 很多代码...
    if someCondition {
        return  // 不清楚返回什么
    }
    // 更多代码...
    return
}

// 推荐:显式返回
func process(data []int) (result int, err error) {
    // 很多代码...
    if someCondition {
        return 0, errors.New("some error")
    }
    // 更多代码...
    return result, nil
}

6.3 defer与命名返回值 #

go
func example() (result int) {
    defer func() {
        result++  // 修改命名返回值
    }()
    return 10  // 返回11
}

七、最佳实践 #

7.1 错误放在最后 #

go
func doSomething() (result int, err error) {
    // ...
}

7.2 短函数使用裸返回 #

go
func divmod(a, b int) (q, r int) {
    q, r = a/b, a%b
    return
}

7.3 长函数显式返回 #

go
func process(data []int) (int, error) {
    if len(data) == 0 {
        return 0, errors.New("empty data")
    }
    
    result := 0
    for _, v := range data {
        result += v
    }
    
    return result, nil
}

7.4 使用有意义的命名 #

go
// 好
func parse(s string) (name string, age int, err error) {}

// 不好
func parse(s string) (s1 string, i1 int, e error) {}

八、总结 #

多返回值要点:

特性 说明
多返回值 函数可以返回多个值
命名返回值 为返回值命名,提高可读性
裸返回 命名返回值可以省略return后的值
自动初始化 命名返回值自动初始化为零值

关键点:

  1. 多返回值:Go的特色功能
  2. 命名返回值:提高代码可读性
  3. 裸返回:短函数可用,长函数避免
  4. 错误放最后:约定俗成的模式
  5. defer修改:defer可以修改命名返回值

准备好学习匿名函数与闭包了吗?让我们进入下一章!

最后更新:2026-03-26