多返回值 #
一、多返回值概述 #
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后的值 |
| 自动初始化 | 命名返回值自动初始化为零值 |
关键点:
- 多返回值:Go的特色功能
- 命名返回值:提高代码可读性
- 裸返回:短函数可用,长函数避免
- 错误放最后:约定俗成的模式
- defer修改:defer可以修改命名返回值
准备好学习匿名函数与闭包了吗?让我们进入下一章!
最后更新:2026-03-26