Go学习笔记:函数与控制流——多返回值、for 与 if 的独特语法

0 阅读3分钟

一、函数

1.1 基本语法

Go 的声明和 C/Java 最大的区别是:类型写在变量名后面

// C/Java:   int add(int a, int b)
// Go:       func add(a int, b int) int

func add(a int, b int) int {
    return a + b
}

当连续参数类型相同时,可以省略前面的类型:

func add(a, b int) int {   // a 和 b 都是 int
    return a + b
}

1.2 多返回值(Go 的特色)

Go 没有异常(try-catch),错误通过返回值传递:

func div(a, b int) (int, error) {
    if b == 0 {
        return 0, errors.New("除数不能为 0")
    }
    return a / b, nil   // nil 表示没有错误
}

调用时必须接收所有返回值

result, err := div(10, 3)
if err != nil {
    fmt.Println("出错:", err)
} else {
    fmt.Println(result)   // 3
}

// 用 _ 忽略不需要的返回值
single, _ := div(9, 2)    // 只想要商,忽略余数/错误

💡 nil 是 Go 的"空值",类似其他语言的 nullerror 为 nil 表示没有错误。

1.3 命名返回值

可以在函数签名里就给返回值起好名字,函数体里直接赋值,最后 return 即可:

func sumAndCount(nums ...int) (total int, count int) {
    for _, n := range nums {
        total += n    // total 已经声明好了
        count++       // count 也声明好了
    }
    return            // 自动返回 total 和 count
}

什么时候用命名返回值?

  • 返回值含义需要明确命名来说明时
  • 简单函数可以少写一些变量声明
  • 不要滥用——函数太复杂时命名返回值反而降低可读性

1.4 可变参数

func sum(nums ...int) int {   // ...int 表示可变参数
    total := 0
    for _, n := range nums {
        total += n
    }
    return total
}

sum(1, 2)           // 3
sum(1, 2, 3, 4, 5)  // 15

二、控制流

2.1 for — Go 唯一的循环

Go 只有 for,没有 whiledo-while

经典三段式:

for i := 0; i < 5; i++ {
    fmt.Println(i)   // 0, 1, 2, 3, 4
}

替代 while:

n := 0
for n < 3 {          // 只写条件,省略前后
    fmt.Println(n)
    n++
}

死循环:

for {
    // 一直执行,直到 break
    if 条件 {
        break
    }
}

for range 遍历:

names := []string{"Go", "Python", "Rust"}

// 同时取 index 和 value
for i, lang := range names {
    fmt.Printf("%d: %s\n", i, lang)
}

// 只要 value,不要 index
for _, lang := range names {
    fmt.Println(lang)
}

// 只要 index
for i := range names {
    fmt.Println(i)
}

2.2 if — 条件不需要括号

age := 20
if age >= 18 {
    fmt.Println("已成年")
} else {
    fmt.Println("未成年")
}

⚠️ 条件不能加括号——加括号反而让 Go 觉得别扭,这是和其他语言最大的视觉差异。

if 的独特用法:先执行一个短语句,再判断

if score := 85; score >= 60 {
    fmt.Println("及格,得分:", score)
} else {
    fmt.Println("不及格,得分:", score)
}
// 这里用不了 score,它只活在 if/else 里

这种写法的好处:把「获取值」和「判断」写在一起,变量作用域限制在 if 块内,防止误用。

2.3 switch

day := 3
switch day {
case 1:
    fmt.Println("周一")
case 2:
    fmt.Println("周二")
case 3:
    fmt.Println("周三")
default:
    fmt.Println("其他")
}

Go 的 switch 和 C 不同:每个 case 自动 break,不需要写 break。如果想继续执行下一个 case,可以用 fallthrough(很少用)。


三、完整示例

把今天学的串起来:

package main

import (
    "errors"
    "fmt"
)

// 检查分数是否及格
func checkScore(name string, score int) (string, error) {
    if score < 0 || score > 100 {
        return "", errors.New("分数必须在 0-100 之间")
    }
    
    result := "不及格"
    if score >= 60 {
        result = "及格"
    }
    return fmt.Sprintf("%s: %s", name, result), nil
}

func main() {
    students := []int{85, 42, 93, -5}
    
    for i, score := range students {
        names := []string{"张三", "李四", "王五", "赵六"}
        
        if result, err := checkScore(names[i], score); err != nil {
            fmt.Printf("❌ %s 数据异常: %s\n", names[i], err)
        } else {
            fmt.Printf("✅ %s\n", result)
        }
    }
}

输出:

✅ 张三: 及格
✅ 李四: 不及格
✅ 王五: 及格
❌ 赵六 数据异常: 分数必须在 0-100 之间

四、小结

知识点要点
函数参数类型写在变量名后面
多返回值(int, error) — 不用异常传递错误
命名返回值提前声明,直接 return
可变参数nums ...int
for唯一循环,三段式 / 类 while / 死循环 / range
if不用括号,支持短语句
switch默认自动 break