一、函数
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 的"空值",类似其他语言的null。error为 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,没有 while 和 do-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 |