以下是第三周流程控制与FizzBuzz游戏的详细教程,包含完整语法讲解和分步实现指南:
第三周:流程控制与FizzBuzz实现
一、if/else条件判断
1. 基本语法
if 条件表达式 {
// true时执行
} else if 其他条件 {
// 其他分支
} else {
// 默认分支
}
2. 重要特性
- 条件不需要括号:
if (x>5) ❌
→if x>5 ✅
- 必须使用花括号:即使只有一行代码
- 支持变量初始化:
if num := getNumber(); num > 0 {
fmt.Println("正数")
}
3. 示例:成绩评级
func gradeCheck(score int) string {
if score >= 90 {
return "A"
} else if score >= 80 {
return "B"
} else if score >= 60 {
return "C"
} else {
return "D"
}
}
二、for循环
1. 三种形式
形式 | 等效其他语言 | 示例 |
---|---|---|
for 初始化;条件;后置 | 传统for | for i:=0; i<5; i++ |
for 条件 | while | for x < 100 |
for { ... } | 无限循环 | 需配合break 使用 |
2. range遍历
// 遍历切片
nums := []int{2,4,6}
for index, value := range nums {
fmt.Printf("索引:%d 值:%d\n", index, value)
}
// 遍历字符串(按rune遍历)
str := "Go语言"
for pos, char := range str {
fmt.Printf("%d: %c\n", pos, char)
}
3. 控制语句
break
:立即终止循环continue
:跳过本次迭代return
:退出当前函数
三、FizzBuzz任务实现
游戏规则
- 输入数字n,输出1到n的序列
- 当数是3的倍数 → 输出"Fizz"
- 当数是5的倍数 → 输出"Buzz"
- 同时满足 → 输出"FizzBuzz"
分步教程
- 创建项目目录
mkdir fizzbuzz
cd fizzbuzz
go mod init fizzbuzz
- 编写代码(main.go)
package main
import (
"fmt"
"strconv"
)
func main() {
var n int
fmt.Print("请输入最大数字:")
fmt.Scanln(&n)
for i := 1; i <= n; i++ {
output := ""
// 条件判断顺序很重要!
if i%3 == 0 && i%5 == 0 {
output = "FizzBuzz"
} else if i%3 == 0 {
output = "Fizz"
} else if i%5 == 0 {
output = "Buzz"
} else {
output = strconv.Itoa(i) // 数字转字符串
}
fmt.Print(output + " ")
}
fmt.Println() // 输出换行
}
- 运行测试
go run main.go
# 输入:15
# 预期输出:
# 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz
四、关键知识点
- 取余运算符:
%
用于判断倍数关系 - 逻辑运算符:
&&
(且)、||
(或) - 类型转换:使用
strconv
包进行数字与字符串转换 - 循环优化:使用
strings.Builder
提升大量字符串拼接效率(进阶)
五、常见问题解决
-
顺序错误导致逻辑异常
错误示例:先判断3的倍数再判断5的倍数,导致15的倍数显示Fizz而不是FizzBuzz -
无限循环问题
for { // 缺少退出条件 fmt.Println("卡死循环") }
-
range遍历陷阱
// 直接修改遍历值无效 for _, num := range nums { num *= 2 // 不影响原切片 }
-
字符串转换方法
strconv.Itoa()
:int→stringstrconv.Atoi()
:string→int(需错误处理)
学习成果检查
- 能正确编写嵌套条件判断
- 会使用for循环的三种形式
- 程序正确处理15的倍数情况
- 输出格式正确(数字与单词混合)
- 理解range返回的索引和值
扩展练习:
- 添加命令行参数支持(使用flag包)
- 实现反向FizzBuzz(输入单词返回对应数字)
- 支持自定义规则(如7的倍数输出"Jazz")
完成本练习后,你将熟练掌握Go语言的流程控制结构,能够处理各种条件判断和循环场景。
以下为扩展学习内容:
以下是第三周流程控制的增强版教程,包含更多示例和详细说明:
第三周:流程控制深度解析
一、if/else条件判断扩展
1. 复合条件判断
// 示例1:登录验证系统
func login(username, password string) string {
if len(username) < 5 || len(password) < 8 { // 或运算符
return "账号或密码长度不足"
} else if username == "admin" && password == "Admin@123" { // 与运算符
return "管理员登录成功"
} else if !strings.Contains(password, "@") { // 非运算符
return "密码必须包含@符号"
} else {
return "普通用户登录成功"
}
}
// 测试用例
fmt.Println(login("user1", "pass")) // 长度不足
fmt.Println(login("admin", "wrongpass")) // 密码错误
fmt.Println(login("user2", "secure@pw")) // 成功
2. 带初始化的条件判断
// 示例2:文件扩展名检查
if file, err := os.Open("data.txt"); err != nil { // 初始化变量
fmt.Println("文件打开失败:", err)
} else if ext := filepath.Ext(file.Name()); ext != ".txt" { // 链式判断
fmt.Println("仅支持txt文件")
} else {
defer file.Close()
// 处理文件内容...
}
二、for循环深度应用
1. 不同循环形式对比
// 形式1:传统计数器循环
for i := 0; i < 5; i++ {
fmt.Print(i, " ") // 输出: 0 1 2 3 4
}
// 形式2:类似while的循环
sum := 1
for sum < 1000 { // 等效while(sum < 1000)
sum += sum
}
// 形式3:无限循环
for {
fmt.Print("请输入命令(q退出): ")
var input string
fmt.Scanln(&input)
if input == "q" {
break // 退出循环
}
// 处理命令...
}
2. range遍历进阶
// 示例3:遍历map
colors := map[string]string{
"red": "#FF0000",
"green": "#00FF00",
"blue": "#0000FF",
}
for key, value := range colors {
fmt.Printf("%-6s -> %s\n", key, value)
}
/* 可能输出(顺序不固定):
red -> #FF0000
green -> #00FF00
blue -> #0000FF
*/
// 示例4:遍历字符串(处理多字节字符)
str := "中文汉字"
for i, r := range str { // r的类型是rune
fmt.Printf("位置%d: %c (Unicode: %U)\n", i, r, r)
}
/* 输出:
位置0: 中 (Unicode: U+4E2D)
位置3: 文 (Unicode: U+6587) // 注意中文字符占3字节
位置6: 汉 (Unicode: U+6C49)
位置9: 字 (Unicode: U+5B57)
*/
三、FizzBuzz任务扩展实现
版本1:基础实现
// 已在前次回复中提供的基础版本
版本2:使用switch优化
func fizzbuzzSwitch(n int) {
for i := 1; i <= n; i++ {
switch {
case i%15 == 0: // 先判断最大公约数
fmt.Print("FizzBuzz ")
case i%3 == 0:
fmt.Print("Fizz ")
case i%5 == 0:
fmt.Print("Buzz ")
default:
fmt.Printf("%d ", i)
}
}
}
版本3:高性能字符串构建
func fizzbuzzEfficient(n int) {
var builder strings.Builder // 高效字符串构建器
for i := 1; i <= n; i++ {
switch {
case i%15 == 0:
builder.WriteString("FizzBuzz")
case i%3 == 0:
builder.WriteString("Fizz")
case i%5 == 0:
builder.WriteString("Buzz")
default:
builder.WriteString(strconv.Itoa(i))
}
builder.WriteByte(' ') // 添加空格分隔
}
fmt.Println(builder.String())
}
四、调试技巧与常见错误
1. 调试打印技巧
// 在复杂条件中插入调试语句
if i%3 == 0 {
fmt.Printf("[DEBUG] i=%d 触发3的倍数\n", i)
output += "Fizz"
}
2. 常见错误分析
错误1:条件顺序不当
// 错误代码:先判断3的倍数会导致15的倍数被错误标记为Fizz
if i%3 == 0 {
// ...
} else if i%5 == 0 {
// ...
}
错误2:无限循环
// 缺少终止条件的无限循环
for i := 0; i < 5; { // 缺少i++会导致无限循环
fmt.Println(i)
}
错误3:range值拷贝
// 直接修改range返回的value不会影响原切片
nums := []int{1, 2, 3}
for _, num := range nums {
num *= 2 // 无效操作
}
fmt.Println(nums) // 输出仍是[1 2 3]
五、扩展练习
-
增强版FizzBuzz:
- 添加7的倍数输出"Jazz"
- 质数显示为"Prime"
- 支持自定义规则配置文件
-
购物车系统:
// 使用循环和条件实现以下功能: // - 显示商品列表(使用map存储) // - 用户输入商品ID和数量 // - 计算总金额(满100减20) // - 显示购物清单和最终价格
六、学习成果检查表
- 能正确编写包含逻辑运算符的复合条件
- 会使用带初始化的条件语句
- 能实现不同形式的for循环
- 理解map遍历的随机性特征
- 会处理多字节字符的遍历
- 能解释switch的fallthrough用法
- 理解strings.Builder的性能优势
通过这两个详细示例和多种实现版本,你可以更深入地掌握Go的流程控制机制。建议在本地实际运行每个示例,并尝试修改参数观察不同结果,这是理解控制结构的最佳方式。