4·基础入门入门

if/else 与循环

ifforswitchrange

Go 并发编程 - 第 4 课:if/else 与循环

1. 学习目标

通过本课学习,你将能够:

  1. 掌握条件判断:熟练使用 if/else 语句处理程序中的分支逻辑
  2. 精通循环控制:理解 for 循环的多种用法,包括计数循环、条件循环和无限循环
  3. 灵活运用 switch:使用 switch 语句简化多条件判断,理解 fallthrough 关键字
  4. 掌握 range 遍历:使用 range 关键字高效遍历数组、切片、字符串、映射等数据结构
  5. 避免常见陷阱:识别并避免初学者在条件判断和循环中常犯的错误

2. 核心概念

2.1 if/else 条件判断

if/else 是程序中最基本的控制结构,用于根据条件执行不同的代码块。

基本语法:

if condition {
    // 条件为真时执行
} else if anotherCondition {
    // 另一个条件为真时执行
} else {
    // 所有条件都不满足时执行
}

特点:

  • 条件表达式不需要用括号包裹
  • 大括号 {} 是必须的,即使只有一行代码
  • 可以包含多个 else if 分支
  • 支持在 if 前声明变量(仅在 if 作用域内有效)

2.2 for 循环

Go 语言中只有 for 一种循环结构,但功能非常强大。

三种基本形式:

// 1. 传统的三段式循环
for i := 0; i < 10; i++ {
    // 计数循环
}

// 2. 条件循环(类似 while)
for condition {
    // 条件为真时继续循环
}

// 3. 无限循环
for {
    // 永远循环,需要 break 退出
}

2.3 switch 语句

switch 语句用于多分支选择,比多个 if-else 更清晰。

特点:

  • 每个 case 自动 break,不会"穿透"到下一个 case
  • 可以使用 fallthrough 强制执行下一个 case
  • case 可以是多个值(用逗号分隔)
  • 支持无条件的 switch(替代长 if-else 链)

2.4 range 关键字

range 用于遍历各种数据结构,是 Go 中处理集合的常用方式。

可遍历的类型:

  • 数组和切片:返回索引和值
  • 字符串:返回索引和 Unicode 码点
  • 映射:返回键和值
  • 通道:返回接收到的值(并发编程中重要)

3. 代码示例

3.1 if/else 示例

package main

import "fmt"

func main() {
    // 基本的 if/else
    temperature := 25
    if temperature > 30 {
        fmt.Println("天气很热,开空调!")
    } else if temperature > 20 {
        fmt.Println("天气不错,适合户外活动")
    } else {
        fmt.Println("有点冷,多穿点衣服")
    }
    
    // 带初始化语句的 if
    if hour := 14; hour < 12 {
        fmt.Println("现在是上午")
    } else {
        fmt.Println("现在是下午")
    }
}

3.2 for 循环示例

package main

import "fmt"

func main() {
    // 计数循环
    fmt.Println("1. 计数循环:")
    for i := 1; i <= 5; i++ {
        fmt.Printf("%d ", i)
    }
    fmt.Println()
    
    // 条件循环(类似 while)
    fmt.Println("2. 条件循环:")
    count := 0
    for count < 3 {
        fmt.Printf("循环第 %d 次\n", count+1)
        count++
    }
    
    // 无限循环与 break
    fmt.Println("3. 无限循环:")
    i := 0
    for {
        if i >= 3 {
            break // 跳出循环
        }
        fmt.Printf("无限循环第 %d 次\n", i+1)
        i++
    }
    
    // 使用 continue 跳过本次循环
    fmt.Println("4. 使用 continue:")
    for i := 0; i < 5; i++ {
        if i == 2 {
            continue // 跳过本次循环
        }
        fmt.Printf("%d ", i)
    }
    fmt.Println()
}

3.3 switch 语句示例

package main

import "fmt"

func main() {
    // 基本的 switch
    day := "Wednesday"
    
    switch day {
    case "Monday", "Tuesday", "Wednesday", "Thursday", "Friday":
        fmt.Println("今天是工作日")
    case "Saturday", "Sunday":
        fmt.Println("今天是周末")
    default:
        fmt.Println("无效的日期")
    }
    
    // 无表达式的 switch(替代 if-else 链)
    score := 85
    
    switch {
    case score >= 90:
        fmt.Println("优秀")
    case score >= 80:
        fmt.Println("良好")
    case score >= 70:
        fmt.Println("中等")
    case score >= 60:
        fmt.Println("及格")
    default:
        fmt.Println("不及格")
    }
    
    // fallthrough 示例
    num := 1
    switch num {
    case 1:
        fmt.Println("匹配 case 1")
        fallthrough // 继续执行下一个 case
    case 2:
        fmt.Println("匹配 case 2 或 fallthrough 到这里")
    case 3:
        fmt.Println("匹配 case 3")
    }
}

3.4 range 遍历示例

package main

import "fmt"

func main() {
    // 遍历数组
    colors := [3]string{"Red", "Green", "Blue"}
    fmt.Println("遍历数组:")
    for index, color := range colors {
        fmt.Printf("索引: %d, 值: %s\n", index, color)
    }
    
    // 遍历切片
    nums := []int{10, 20, 30, 40, 50}
    fmt.Println("\n遍历切片:")
    for i, v := range nums {
        fmt.Printf("nums[%d] = %d\n", i, v)
    }
    
    // 遍历字符串
    str := "Go语言"
    fmt.Println("\n遍历字符串:")
    for i, c := range str {
        fmt.Printf("索引: %d, Unicode: %U, 字符: %c\n", i, c, c)
    }
    
    // 遍历映射
    studentScores := map[string]int{
        "Alice": 90,
        "Bob":   85,
        "Carol": 92,
    }
    
    fmt.Println("\n遍历映射:")
    for name, score := range studentScores {
        fmt.Printf("%s 的成绩是 %d 分\n", name, score)
    }
    
    // 忽略索引或值
    fmt.Println("\n只获取值:")
    for _, v := range nums {
        fmt.Printf("%d ", v)
    }
    fmt.Println()
}

4. 实践练习

练习 1:成绩等级判断(简单)

编写程序,输入一个 0-100 之间的成绩分数,输出对应的等级:

  • 90-100: A
  • 80-89: B
  • 70-79: C
  • 60-69: D
  • 0-59: F
// 预期输出示例:
// 输入: 85
// 输出: 等级为: B

// 输入: 92
// 输出: 等级为: A

练习 2:九九乘法表(中等)

使用 for 循环打印完整的九九乘法表。

// 预期输出:
// 1*1=1
// 1*2=2  2*2=4
// 1*3=3  2*3=6  3*3=9
// ...

练习 3:统计字符频率(较难)

编写程序,输入一个字符串,使用 for range 遍历并统计每个字符出现的次数,然后输出出现频率最高的字符及其出现次数。

// 预期输出示例:
// 输入: "hello world"
// 输出: 字符 'l' 出现了 3 次

5. 常见错误

5.1 if 语句的常见错误

// 错误 1:条件表达式忘记括号(Go 中不需要括号)
// 错误写法:
if (x > 10) {
    // ...
}

// 正确写法:
if x > 10 {
    // ...
}

// 错误 2:赋值符号误用为比较符号
x := 5
// 错误写法:这会将 10 赋值给 x,而不是比较
if x = 10 {
    // 这行代码会报错,因为 x = 10 返回的是 10(bool 类型)
}

// 正确写法:
if x == 10 {
    // ...
}

5.2 for 循环的常见错误

// 错误 1:循环变量作用域问题
for i := 0; i < 10; i++ {
    // 这里的 i 在循环结束后就不能访问了
}
// fmt.Println(i) // 错误:i 未定义

// 错误 2:无限循环忘记退出条件
count := 0
for count < 10 {
    // 忘记增加 count,导致无限循环
    // count++ 忘记写了!
    fmt.Println(count)
}

5.3 switch 语句的常见错误

// 错误 1:误以为需要 break(Go 中每个 case 自动 break)
switch num {
case 1:
    fmt.Println("一")
    break // 这行是多余的,但不会出错
case 2:
    fmt.Println("二")
}

// 错误 2:误用 fallthrough
switch num {
case 1:
    fmt.Println("一")
    fallthrough // 即使下一个 case 不匹配也会执行
case 2:
    fmt.Println("二") // 当 num=1 时,这里也会执行
}

5.4 range 遍历的常见错误

// 错误:忽略 range 的返回值
// 错误写法:
for range nums {
    // 只知道遍历了多少次,不知道具体值
}

// 正确写法:
for i, v := range nums {
    fmt.Printf("索引 %d, 值 %d\n", i, v)
}

// 错误:在遍历中修改映射可能导致问题
m := map[string]int{"a": 1, "b": 2}
for k, v := range m {
    if v == 1 {
        delete(m, k) // 在遍历中删除元素是安全的
    }
}

6. 小结

本课学习了 Go 语言中最基本的控制结构:

关键要点:

  1. if/else 条件判断

    • 使用 if 处理条件分支
    • 支持 else ifelse
    • 可以在 if 前声明变量(限定作用域)
  2. for 循环

    • Go 中唯一的循环结构
    • 三种形式:计数循环、条件循环、无限循环
    • 使用 break 退出循环,continue 跳过当前迭代
  3. switch 语句

    • 多分支选择,比多个 if-else 更清晰
    • 每个 case 自动 break
    • 支持无条件的 switch(替代 if-else 链)
    • 使用 fallthrough 继续执行下一个 case
  4. range 遍历

    • 遍历数组、切片、字符串、映射等
    • 返回索引和值(可使用 _ 忽略不需要的)
    • 是处理集合数据的首选方式

最佳实践:

  1. 保持条件判断清晰简洁
  2. 避免过深的嵌套(超过 3 层考虑重构)
  3. 优先使用 switch 替代长 if-else
  4. 使用 range 遍历集合,代码更简洁安全
  5. 注意循环中的边界条件,避免死循环或越界

掌握了这些控制结构,你就能编写出逻辑清晰、结构良好的 Go 程序了。下一课我们将学习数组与切片,继续探索 Go 语言的数据结构。

练习编辑器

go
Loading...

继续学习

完成本课后,建议继续学习下一课「数组与切片」 以巩固所学知识。