50周学习go语言:第三周 流程控制与FizzBuzz实现

news/2025/2/24 14:22:09

以下是第三周流程控制与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 初始化;条件;后置传统forfor i:=0; i<5; i++
for 条件whilefor 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"
分步教程
  1. 创建项目目录
mkdir fizzbuzz
cd fizzbuzz
go mod init fizzbuzz
  1. 编写代码(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() // 输出换行
}
  1. 运行测试
go run main.go
# 输入:15
# 预期输出:
# 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 

四、关键知识点

  1. 取余运算符% 用于判断倍数关系
  2. 逻辑运算符&&(且)、||(或)
  3. 类型转换:使用strconv包进行数字与字符串转换
  4. 循环优化:使用strings.Builder提升大量字符串拼接效率(进阶)

五、常见问题解决

  1. 顺序错误导致逻辑异常
    错误示例:先判断3的倍数再判断5的倍数,导致15的倍数显示Fizz而不是FizzBuzz

  2. 无限循环问题

    for { // 缺少退出条件
        fmt.Println("卡死循环")
    }
    
  3. range遍历陷阱

    // 直接修改遍历值无效
    for _, num := range nums {
        num *= 2 // 不影响原切片
    }
    
  4. 字符串转换方法

    • strconv.Itoa():int→string
    • strconv.Atoi():string→int(需错误处理)

学习成果检查

  • 能正确编写嵌套条件判断
  • 会使用for循环的三种形式
  • 程序正确处理15的倍数情况
  • 输出格式正确(数字与单词混合)
  • 理解range返回的索引和值

扩展练习

  1. 添加命令行参数支持(使用flag包)
  2. 实现反向FizzBuzz(输入单词返回对应数字)
  3. 支持自定义规则(如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]

五、扩展练习

  1. 增强版FizzBuzz

    • 添加7的倍数输出"Jazz"
    • 质数显示为"Prime"
    • 支持自定义规则配置文件
  2. 购物车系统

    // 使用循环和条件实现以下功能:
    // - 显示商品列表(使用map存储)
    // - 用户输入商品ID和数量
    // - 计算总金额(满100减20)
    // - 显示购物清单和最终价格
    

六、学习成果检查表

  • 能正确编写包含逻辑运算符的复合条件
  • 会使用带初始化的条件语句
  • 能实现不同形式的for循环
  • 理解map遍历的随机性特征
  • 会处理多字节字符的遍历
  • 能解释switch的fallthrough用法
  • 理解strings.Builder的性能优势

通过这两个详细示例和多种实现版本,你可以更深入地掌握Go的流程控制机制。建议在本地实际运行每个示例,并尝试修改参数观察不同结果,这是理解控制结构的最佳方式。


http://www.niftyadmin.cn/n/5864455.html

相关文章

【MySQL 一 数据库基础】深入解析 MySQL 的索引(2)

索引 MySQL中的页 为什么要使用页&#xff1f; 在.ibd文件中最重要的结构体就是Page(页)&#xff0c;页是内存与磁盘交互的最小单元&#xff0c;默认大小为16KB&#xff0c;每次内存与磁盘的交互至少读取一页&#xff0c;&#xff0c;所以在磁盘中每个页内部的地址都是连续的; …

(五)趣学设计模式 之 建造者模式!

目录 一、 啥是建造者模式&#xff1f;二、 为什么要用建造者模式&#xff1f;三、 建造者模式怎么实现&#xff1f;四、 建造者模式的应用场景五、 建造者模式的优点和缺点六、 总结 &#x1f31f;我的其他文章也讲解的比较有趣&#x1f601;&#xff0c;如果喜欢博主的讲解方…

STM32的HAL库开发---ADC采集内部温度传感器

一、STM32内部温度传感器简介 二、温度计算方法 F1系列&#xff1a; 从数据手册中可以找到V25和Avg_Slope F4、F7、H7系列只是标准值不同&#xff0c;自行查阅手册 三、实验简要 1、功能描述 通过ADC1通道16采集芯片内部温度传感器的电压&#xff0c;将电压值换算成温度后&…

垂类大模型微调(二):使用LLaMA-Factory

上一篇博文和大家一起安装了LLaMA-Factory工具,并下载了大模型在上面进行了简单的加载和推理,今天尝试通过LoRa技术对大模型进行微调; 一、训练集准备 1.1 介绍训练集结构 这里演示对Qwen2.5-0.5B-Instruct-GPTQ-Int4模型进行LoRA微调, 大家可以根据垂类大模型微调(一)…

LeetCode 热题 100 560. 和为 K 的子数组

LeetCode 热题 100 | 560. 和为 K 的子数组 大家好&#xff0c;今天我们来解决一道经典的算法题——和为 K 的子数组。这道题在 LeetCode 上被标记为中等难度&#xff0c;要求我们统计数组中所有和为 k 的连续子数组的个数。下面我将详细讲解解题思路&#xff0c;并附上 Pytho…

缓存基础解释与缓存友好型编程基础

讨论了如何使用快速核心内存&#xff08;约32,000个字&#xff09;作为更大、更慢的核心内存&#xff08;约1,000,000个字&#xff09;的从属内存&#xff08;slave&#xff09;。 通过这种方式&#xff0c;可以在实际使用案例中设计出接近于更快内存的有效访问时间&#xff08…

Vue 3 + Vite 项目中配置代理解决开发环境中跨域请求问题

在 Vue 3 Vite 项目中&#xff0c;配置代理是解决开发环境中跨域请求问题的常见方法。通过在 Vite 的配置文件中设置代理&#xff0c;可以将前端请求转发到后端服务器&#xff0c;从而避免浏览器的同源策略限制。 1. 创建 Vue 3 Vite 项目 首先&#xff0c;确保你已经安装了…

广东英语十二种应用文模版范文

1. 邀请信&#xff08;Invitation Letter&#xff09; 模版 Dear [Recipients Name],I hope this letter finds you well. I am writing to invite you to [Event Name] which will be held on [Date] at [Location]. The event will start at [Time] and we would be deligh…