初始提交
This commit is contained in:
485
golang-learning/02-control-flow/01-if-else.go
Normal file
485
golang-learning/02-control-flow/01-if-else.go
Normal file
@@ -0,0 +1,485 @@
|
||||
/*
|
||||
01-if-else.go - Go 语言条件语句详解
|
||||
|
||||
学习目标:
|
||||
1. 掌握 if 语句的基本用法
|
||||
2. 理解 if-else 和 if-else if 结构
|
||||
3. 学会在 if 语句中声明变量
|
||||
4. 了解条件表达式的写法
|
||||
5. 掌握嵌套条件语句
|
||||
|
||||
知识点:
|
||||
- if 语句基本语法
|
||||
- if-else 语句
|
||||
- if-else if-else 链
|
||||
- if 语句中的变量声明
|
||||
- 条件表达式
|
||||
- 嵌套 if 语句
|
||||
- 实际应用场景
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== Go 语言条件语句详解 ===\n")
|
||||
|
||||
// 演示基本 if 语句
|
||||
demonstrateBasicIf()
|
||||
|
||||
// 演示 if-else 语句
|
||||
demonstrateIfElse()
|
||||
|
||||
// 演示 if-else if 链
|
||||
demonstrateIfElseIf()
|
||||
|
||||
// 演示 if 语句中的变量声明
|
||||
demonstrateIfWithDeclaration()
|
||||
|
||||
// 演示嵌套 if 语句
|
||||
demonstrateNestedIf()
|
||||
|
||||
// 演示复杂条件表达式
|
||||
demonstrateComplexConditions()
|
||||
|
||||
// 演示实际应用示例
|
||||
demonstratePracticalExamples()
|
||||
}
|
||||
|
||||
// demonstrateBasicIf 演示基本 if 语句
|
||||
func demonstrateBasicIf() {
|
||||
fmt.Println("1. 基本 if 语句:")
|
||||
|
||||
// 最简单的 if 语句
|
||||
age := 18
|
||||
if age >= 18 {
|
||||
fmt.Printf(" 年龄 %d >= 18,已成年\n", age)
|
||||
}
|
||||
|
||||
// 条件为 false 的情况
|
||||
score := 45
|
||||
if score >= 60 {
|
||||
fmt.Printf(" 分数 %d >= 60,及格\n", score)
|
||||
}
|
||||
fmt.Printf(" 分数 %d < 60,条件不满足,if 块不执行\n", score)
|
||||
|
||||
// 布尔变量作为条件
|
||||
isLoggedIn := true
|
||||
if isLoggedIn {
|
||||
fmt.Printf(" 用户已登录\n")
|
||||
}
|
||||
|
||||
// 函数返回值作为条件
|
||||
if isEven(10) {
|
||||
fmt.Printf(" 10 是偶数\n")
|
||||
}
|
||||
|
||||
// 注意:Go 的 if 语句不需要括号,但需要大括号
|
||||
fmt.Printf(" 注意: Go 的 if 条件不需要括号,但大括号是必需的\n")
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateIfElse 演示 if-else 语句
|
||||
func demonstrateIfElse() {
|
||||
fmt.Println("2. if-else 语句:")
|
||||
|
||||
// 基本 if-else
|
||||
temperature := 25
|
||||
if temperature > 30 {
|
||||
fmt.Printf(" 温度 %d°C,天气炎热\n", temperature)
|
||||
} else {
|
||||
fmt.Printf(" 温度 %d°C,天气凉爽\n", temperature)
|
||||
}
|
||||
|
||||
// 数值比较
|
||||
a, b := 10, 20
|
||||
if a > b {
|
||||
fmt.Printf(" %d > %d\n", a, b)
|
||||
} else {
|
||||
fmt.Printf(" %d <= %d\n", a, b)
|
||||
}
|
||||
|
||||
// 字符串比较
|
||||
password := "123456"
|
||||
if password == "admin123" {
|
||||
fmt.Printf(" 密码正确\n")
|
||||
} else {
|
||||
fmt.Printf(" 密码错误\n")
|
||||
}
|
||||
|
||||
// 布尔值判断
|
||||
hasPermission := false
|
||||
if hasPermission {
|
||||
fmt.Printf(" 有权限访问\n")
|
||||
} else {
|
||||
fmt.Printf(" 没有权限访问\n")
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateIfElseIf 演示 if-else if 链
|
||||
func demonstrateIfElseIf() {
|
||||
fmt.Println("3. if-else if-else 链:")
|
||||
|
||||
// 成绩等级判断
|
||||
score := 85
|
||||
fmt.Printf(" 分数: %d\n", score)
|
||||
if score >= 90 {
|
||||
fmt.Printf(" 等级: A (优秀)\n")
|
||||
} else if score >= 80 {
|
||||
fmt.Printf(" 等级: B (良好)\n")
|
||||
} else if score >= 70 {
|
||||
fmt.Printf(" 等级: C (中等)\n")
|
||||
} else if score >= 60 {
|
||||
fmt.Printf(" 等级: D (及格)\n")
|
||||
} else {
|
||||
fmt.Printf(" 等级: F (不及格)\n")
|
||||
}
|
||||
|
||||
// 年龄段分类
|
||||
age := 25
|
||||
fmt.Printf(" 年龄: %d\n", age)
|
||||
if age < 13 {
|
||||
fmt.Printf(" 年龄段: 儿童\n")
|
||||
} else if age < 20 {
|
||||
fmt.Printf(" 年龄段: 青少年\n")
|
||||
} else if age < 60 {
|
||||
fmt.Printf(" 年龄段: 成年人\n")
|
||||
} else {
|
||||
fmt.Printf(" 年龄段: 老年人\n")
|
||||
}
|
||||
|
||||
// BMI 指数判断
|
||||
weight, height := 70.0, 1.75
|
||||
bmi := weight / (height * height)
|
||||
fmt.Printf(" BMI: %.1f\n", bmi)
|
||||
if bmi < 18.5 {
|
||||
fmt.Printf(" 体重状况: 偏瘦\n")
|
||||
} else if bmi < 24 {
|
||||
fmt.Printf(" 体重状况: 正常\n")
|
||||
} else if bmi < 28 {
|
||||
fmt.Printf(" 体重状况: 偏胖\n")
|
||||
} else {
|
||||
fmt.Printf(" 体重状况: 肥胖\n")
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateIfWithDeclaration 演示 if 语句中的变量声明
|
||||
func demonstrateIfWithDeclaration() {
|
||||
fmt.Println("4. if 语句中的变量声明:")
|
||||
|
||||
// 在 if 语句中声明变量
|
||||
if num := 42; num > 0 {
|
||||
fmt.Printf(" 在 if 中声明: num = %d > 0\n", num)
|
||||
// num 在这个 if 块中可用
|
||||
}
|
||||
// num 在这里不可用
|
||||
|
||||
// 实际应用:字符串转数字
|
||||
str := "123"
|
||||
if value, err := strconv.Atoi(str); err == nil {
|
||||
fmt.Printf(" 字符串 \"%s\" 转换为数字: %d\n", str, value)
|
||||
} else {
|
||||
fmt.Printf(" 字符串 \"%s\" 转换失败: %v\n", str, err)
|
||||
}
|
||||
|
||||
// 检查字符串长度
|
||||
username := "admin"
|
||||
if length := len(username); length >= 5 {
|
||||
fmt.Printf(" 用户名 \"%s\" 长度 %d >= 5,符合要求\n", username, length)
|
||||
} else {
|
||||
fmt.Printf(" 用户名 \"%s\" 长度 %d < 5,太短\n", username, length)
|
||||
}
|
||||
|
||||
// 计算并判断
|
||||
if result := calculateDiscount(1000); result > 0 {
|
||||
fmt.Printf(" 购买金额 1000,折扣: %.2f\n", result)
|
||||
} else {
|
||||
fmt.Printf(" 购买金额 1000,无折扣\n")
|
||||
}
|
||||
|
||||
// 多个变量声明
|
||||
if x, y := 10, 20; x+y > 25 {
|
||||
fmt.Printf(" x=%d, y=%d, x+y=%d > 25\n", x, y, x+y)
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateNestedIf 演示嵌套 if 语句
|
||||
func demonstrateNestedIf() {
|
||||
fmt.Println("5. 嵌套 if 语句:")
|
||||
|
||||
// 用户登录验证
|
||||
username := "admin"
|
||||
password := "123456"
|
||||
isActive := true
|
||||
|
||||
fmt.Printf(" 用户登录验证:\n")
|
||||
if username == "admin" {
|
||||
fmt.Printf(" 用户名正确\n")
|
||||
if password == "123456" {
|
||||
fmt.Printf(" 密码正确\n")
|
||||
if isActive {
|
||||
fmt.Printf(" 账户状态: 活跃\n")
|
||||
fmt.Printf(" 登录成功!\n")
|
||||
} else {
|
||||
fmt.Printf(" 账户状态: 已禁用\n")
|
||||
fmt.Printf(" 登录失败: 账户被禁用\n")
|
||||
}
|
||||
} else {
|
||||
fmt.Printf(" 密码错误\n")
|
||||
fmt.Printf(" 登录失败: 密码不正确\n")
|
||||
}
|
||||
} else {
|
||||
fmt.Printf(" 用户名错误\n")
|
||||
fmt.Printf(" 登录失败: 用户不存在\n")
|
||||
}
|
||||
|
||||
// 数值范围判断
|
||||
number := 15
|
||||
fmt.Printf(" 数值范围判断 (number = %d):\n", number)
|
||||
if number > 0 {
|
||||
fmt.Printf(" 数值为正数\n")
|
||||
if number < 10 {
|
||||
fmt.Printf(" 数值 < 10,属于个位数\n")
|
||||
} else if number < 100 {
|
||||
fmt.Printf(" 数值 < 100,属于两位数\n")
|
||||
} else {
|
||||
fmt.Printf(" 数值 >= 100,属于三位数或更多\n")
|
||||
}
|
||||
} else if number < 0 {
|
||||
fmt.Printf(" 数值为负数\n")
|
||||
} else {
|
||||
fmt.Printf(" 数值为零\n")
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateComplexConditions 演示复杂条件表达式
|
||||
func demonstrateComplexConditions() {
|
||||
fmt.Println("6. 复杂条件表达式:")
|
||||
|
||||
// 逻辑与条件
|
||||
age := 25
|
||||
hasLicense := true
|
||||
hasInsurance := true
|
||||
|
||||
if age >= 18 && hasLicense && hasInsurance {
|
||||
fmt.Printf(" 年龄: %d, 有驾照: %t, 有保险: %t\n", age, hasLicense, hasInsurance)
|
||||
fmt.Printf(" 可以开车\n")
|
||||
}
|
||||
|
||||
// 逻辑或条件
|
||||
isWeekend := false
|
||||
isHoliday := true
|
||||
|
||||
if isWeekend || isHoliday {
|
||||
fmt.Printf(" 周末: %t, 假日: %t\n", isWeekend, isHoliday)
|
||||
fmt.Printf(" 今天不用上班\n")
|
||||
}
|
||||
|
||||
// 复合条件
|
||||
temperature := 28
|
||||
humidity := 70
|
||||
|
||||
if (temperature > 25 && humidity > 60) || temperature > 35 {
|
||||
fmt.Printf(" 温度: %d°C, 湿度: %d%%\n", temperature, humidity)
|
||||
fmt.Printf(" 天气闷热,建议开空调\n")
|
||||
}
|
||||
|
||||
// 字符串条件
|
||||
email := "user@example.com"
|
||||
if strings.Contains(email, "@") && strings.Contains(email, ".") {
|
||||
fmt.Printf(" 邮箱 \"%s\" 格式基本正确\n", email)
|
||||
}
|
||||
|
||||
// 数值范围条件
|
||||
score := 75
|
||||
if score >= 0 && score <= 100 {
|
||||
fmt.Printf(" 分数 %d 在有效范围内\n", score)
|
||||
if score >= 60 {
|
||||
fmt.Printf(" 及格\n")
|
||||
} else {
|
||||
fmt.Printf(" 不及格\n")
|
||||
}
|
||||
} else {
|
||||
fmt.Printf(" 分数 %d 超出有效范围\n", score)
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstratePracticalExamples 演示实际应用示例
|
||||
func demonstratePracticalExamples() {
|
||||
fmt.Println("7. 实际应用示例:")
|
||||
|
||||
// 示例1: 银行账户操作
|
||||
fmt.Printf(" 示例1 - 银行账户操作:\n")
|
||||
balance := 1000.0
|
||||
withdrawAmount := 500.0
|
||||
|
||||
if withdrawAmount > 0 {
|
||||
if withdrawAmount <= balance {
|
||||
balance -= withdrawAmount
|
||||
fmt.Printf(" 取款成功,取款金额: %.2f,余额: %.2f\n", withdrawAmount, balance)
|
||||
} else {
|
||||
fmt.Printf(" 取款失败,余额不足。余额: %.2f,尝试取款: %.2f\n", balance, withdrawAmount)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf(" 取款失败,金额必须大于0\n")
|
||||
}
|
||||
|
||||
// 示例2: 文件权限检查
|
||||
fmt.Printf(" 示例2 - 文件权限检查:\n")
|
||||
const (
|
||||
READ = 1 << 0 // 001
|
||||
WRITE = 1 << 1 // 010
|
||||
EXECUTE = 1 << 2 // 100
|
||||
)
|
||||
|
||||
permissions := READ | WRITE // 011
|
||||
operation := "write"
|
||||
|
||||
if operation == "read" {
|
||||
if permissions&READ != 0 {
|
||||
fmt.Printf(" 允许读取文件\n")
|
||||
} else {
|
||||
fmt.Printf(" 没有读取权限\n")
|
||||
}
|
||||
} else if operation == "write" {
|
||||
if permissions&WRITE != 0 {
|
||||
fmt.Printf(" 允许写入文件\n")
|
||||
} else {
|
||||
fmt.Printf(" 没有写入权限\n")
|
||||
}
|
||||
} else if operation == "execute" {
|
||||
if permissions&EXECUTE != 0 {
|
||||
fmt.Printf(" 允许执行文件\n")
|
||||
} else {
|
||||
fmt.Printf(" 没有执行权限\n")
|
||||
}
|
||||
}
|
||||
|
||||
// 示例3: 购物折扣计算
|
||||
fmt.Printf(" 示例3 - 购物折扣计算:\n")
|
||||
purchaseAmount := 800.0
|
||||
customerLevel := "gold"
|
||||
isFirstPurchase := false
|
||||
|
||||
var discount float64
|
||||
var discountReason string
|
||||
|
||||
if customerLevel == "platinum" {
|
||||
discount = 0.2
|
||||
discountReason = "白金会员"
|
||||
} else if customerLevel == "gold" {
|
||||
discount = 0.15
|
||||
discountReason = "黄金会员"
|
||||
} else if customerLevel == "silver" {
|
||||
discount = 0.1
|
||||
discountReason = "银牌会员"
|
||||
} else {
|
||||
discount = 0.05
|
||||
discountReason = "普通会员"
|
||||
}
|
||||
|
||||
// 首次购买额外折扣
|
||||
if isFirstPurchase {
|
||||
discount += 0.05
|
||||
discountReason += " + 首次购买"
|
||||
}
|
||||
|
||||
// 大额购买额外折扣
|
||||
if purchaseAmount >= 1000 {
|
||||
discount += 0.05
|
||||
discountReason += " + 大额购买"
|
||||
}
|
||||
|
||||
finalAmount := purchaseAmount * (1 - discount)
|
||||
fmt.Printf(" 购买金额: %.2f\n", purchaseAmount)
|
||||
fmt.Printf(" 客户等级: %s\n", customerLevel)
|
||||
fmt.Printf(" 首次购买: %t\n", isFirstPurchase)
|
||||
fmt.Printf(" 折扣原因: %s\n", discountReason)
|
||||
fmt.Printf(" 折扣率: %.1f%%\n", discount*100)
|
||||
fmt.Printf(" 最终金额: %.2f\n", finalAmount)
|
||||
|
||||
// 示例4: 时间段判断
|
||||
fmt.Printf(" 示例4 - 时间段判断:\n")
|
||||
hour := 14
|
||||
|
||||
var timeOfDay string
|
||||
var greeting string
|
||||
|
||||
if hour >= 5 && hour < 12 {
|
||||
timeOfDay = "上午"
|
||||
greeting = "早上好"
|
||||
} else if hour >= 12 && hour < 18 {
|
||||
timeOfDay = "下午"
|
||||
greeting = "下午好"
|
||||
} else if hour >= 18 && hour < 22 {
|
||||
timeOfDay = "晚上"
|
||||
greeting = "晚上好"
|
||||
} else {
|
||||
timeOfDay = "深夜"
|
||||
greeting = "夜深了"
|
||||
}
|
||||
|
||||
fmt.Printf(" 当前时间: %d:00\n", hour)
|
||||
fmt.Printf(" 时间段: %s\n", timeOfDay)
|
||||
fmt.Printf(" 问候语: %s\n", greeting)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// 辅助函数
|
||||
func isEven(n int) bool {
|
||||
return n%2 == 0
|
||||
}
|
||||
|
||||
func calculateDiscount(amount float64) float64 {
|
||||
if amount >= 1000 {
|
||||
return amount * 0.1 // 10% 折扣
|
||||
} else if amount >= 500 {
|
||||
return amount * 0.05 // 5% 折扣
|
||||
}
|
||||
return 0 // 无折扣
|
||||
}
|
||||
|
||||
/*
|
||||
运行这个程序:
|
||||
go run 01-if-else.go
|
||||
|
||||
学习要点:
|
||||
1. if 语句的条件不需要括号,但大括号是必需的
|
||||
2. 可以在 if 语句中声明变量,作用域仅限于 if-else 块
|
||||
3. if-else if-else 链可以处理多个条件分支
|
||||
4. 支持复杂的条件表达式,使用 &&、|| 等逻辑运算符
|
||||
5. 嵌套 if 语句可以处理复杂的逻辑判断
|
||||
6. Go 没有三元运算符,使用 if-else 代替
|
||||
|
||||
最佳实践:
|
||||
1. 条件表达式要清晰易懂
|
||||
2. 避免过深的嵌套,考虑提前返回或使用函数分解
|
||||
3. 复杂条件可以提取为变量或函数
|
||||
4. 使用有意义的变量名和注释
|
||||
5. 考虑使用 switch 语句替代长的 if-else if 链
|
||||
|
||||
常见应用场景:
|
||||
1. 用户输入验证
|
||||
2. 权限检查
|
||||
3. 数值范围判断
|
||||
4. 状态判断
|
||||
5. 错误处理
|
||||
6. 业务逻辑分支
|
||||
*/
|
600
golang-learning/02-control-flow/02-switch.go
Normal file
600
golang-learning/02-control-flow/02-switch.go
Normal file
@@ -0,0 +1,600 @@
|
||||
/*
|
||||
02-switch.go - Go 语言 switch 语句详解
|
||||
|
||||
学习目标:
|
||||
1. 掌握 switch 语句的基本用法
|
||||
2. 理解 Go switch 的特殊特性
|
||||
3. 学会使用 fallthrough 关键字
|
||||
4. 了解类型 switch 的用法
|
||||
5. 掌握无表达式 switch 的使用
|
||||
|
||||
知识点:
|
||||
- switch 基本语法
|
||||
- case 多值匹配
|
||||
- fallthrough 关键字
|
||||
- 类型 switch
|
||||
- 无表达式 switch
|
||||
- switch 中的变量声明
|
||||
- 实际应用场景
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== Go 语言 switch 语句详解 ===\n")
|
||||
|
||||
// 演示基本 switch 语句
|
||||
demonstrateBasicSwitch()
|
||||
|
||||
// 演示多值 case
|
||||
demonstrateMultiValueCase()
|
||||
|
||||
// 演示 fallthrough
|
||||
demonstrateFallthrough()
|
||||
|
||||
// 演示无表达式 switch
|
||||
demonstrateExpressionlessSwitch()
|
||||
|
||||
// 演示类型 switch
|
||||
demonstrateTypeSwitch()
|
||||
|
||||
// 演示 switch 中的变量声明
|
||||
demonstrateSwitchWithDeclaration()
|
||||
|
||||
// 演示实际应用示例
|
||||
demonstratePracticalExamples()
|
||||
}
|
||||
|
||||
// demonstrateBasicSwitch 演示基本 switch 语句
|
||||
func demonstrateBasicSwitch() {
|
||||
fmt.Println("1. 基本 switch 语句:")
|
||||
|
||||
// 基本用法
|
||||
day := 3
|
||||
fmt.Printf(" 今天是星期 %d: ", day)
|
||||
switch day {
|
||||
case 1:
|
||||
fmt.Printf("星期一\n")
|
||||
case 2:
|
||||
fmt.Printf("星期二\n")
|
||||
case 3:
|
||||
fmt.Printf("星期三\n")
|
||||
case 4:
|
||||
fmt.Printf("星期四\n")
|
||||
case 5:
|
||||
fmt.Printf("星期五\n")
|
||||
case 6:
|
||||
fmt.Printf("星期六\n")
|
||||
case 7:
|
||||
fmt.Printf("星期日\n")
|
||||
default:
|
||||
fmt.Printf("无效的日期\n")
|
||||
}
|
||||
|
||||
// 字符串匹配
|
||||
grade := "B"
|
||||
fmt.Printf(" 成绩等级 %s: ", grade)
|
||||
switch grade {
|
||||
case "A":
|
||||
fmt.Printf("优秀 (90-100分)\n")
|
||||
case "B":
|
||||
fmt.Printf("良好 (80-89分)\n")
|
||||
case "C":
|
||||
fmt.Printf("中等 (70-79分)\n")
|
||||
case "D":
|
||||
fmt.Printf("及格 (60-69分)\n")
|
||||
case "F":
|
||||
fmt.Printf("不及格 (0-59分)\n")
|
||||
default:
|
||||
fmt.Printf("无效等级\n")
|
||||
}
|
||||
|
||||
// 字符匹配
|
||||
char := 'a'
|
||||
fmt.Printf(" 字符 '%c' 是: ", char)
|
||||
switch char {
|
||||
case 'a', 'e', 'i', 'o', 'u':
|
||||
fmt.Printf("元音字母\n")
|
||||
default:
|
||||
fmt.Printf("辅音字母或其他字符\n")
|
||||
}
|
||||
|
||||
// Go switch 的特点:自动 break
|
||||
fmt.Printf(" Go switch 特点: 每个 case 自动 break,不会继续执行下一个 case\n")
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateMultiValueCase 演示多值 case
|
||||
func demonstrateMultiValueCase() {
|
||||
fmt.Println("2. 多值 case:")
|
||||
|
||||
// 数字分组
|
||||
number := 4
|
||||
fmt.Printf(" 数字 %d 属于: ", number)
|
||||
switch number {
|
||||
case 1, 3, 5, 7, 9:
|
||||
fmt.Printf("奇数\n")
|
||||
case 2, 4, 6, 8, 10:
|
||||
fmt.Printf("偶数\n")
|
||||
case 0:
|
||||
fmt.Printf("零\n")
|
||||
default:
|
||||
fmt.Printf("其他数字\n")
|
||||
}
|
||||
|
||||
// 月份分组
|
||||
month := 7
|
||||
fmt.Printf(" %d月属于: ", month)
|
||||
switch month {
|
||||
case 12, 1, 2:
|
||||
fmt.Printf("冬季\n")
|
||||
case 3, 4, 5:
|
||||
fmt.Printf("春季\n")
|
||||
case 6, 7, 8:
|
||||
fmt.Printf("夏季\n")
|
||||
case 9, 10, 11:
|
||||
fmt.Printf("秋季\n")
|
||||
default:
|
||||
fmt.Printf("无效月份\n")
|
||||
}
|
||||
|
||||
// 工作日分组
|
||||
weekday := "Saturday"
|
||||
fmt.Printf(" %s 是: ", weekday)
|
||||
switch weekday {
|
||||
case "Monday", "Tuesday", "Wednesday", "Thursday", "Friday":
|
||||
fmt.Printf("工作日\n")
|
||||
case "Saturday", "Sunday":
|
||||
fmt.Printf("周末\n")
|
||||
default:
|
||||
fmt.Printf("无效日期\n")
|
||||
}
|
||||
|
||||
// HTTP 状态码分组
|
||||
statusCode := 404
|
||||
fmt.Printf(" HTTP 状态码 %d: ", statusCode)
|
||||
switch statusCode {
|
||||
case 200, 201, 202, 204:
|
||||
fmt.Printf("成功响应\n")
|
||||
case 301, 302, 304:
|
||||
fmt.Printf("重定向\n")
|
||||
case 400, 401, 403, 404:
|
||||
fmt.Printf("客户端错误\n")
|
||||
case 500, 501, 502, 503:
|
||||
fmt.Printf("服务器错误\n")
|
||||
default:
|
||||
fmt.Printf("其他状态码\n")
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateFallthrough 演示 fallthrough 关键字
|
||||
func demonstrateFallthrough() {
|
||||
fmt.Println("3. fallthrough 关键字:")
|
||||
|
||||
fmt.Printf(" fallthrough 让程序继续执行下一个 case\n")
|
||||
|
||||
score := 85
|
||||
fmt.Printf(" 分数 %d 的评价:\n", score)
|
||||
switch {
|
||||
case score >= 90:
|
||||
fmt.Printf(" 优秀\n")
|
||||
fallthrough
|
||||
case score >= 80:
|
||||
fmt.Printf(" 良好\n")
|
||||
fallthrough
|
||||
case score >= 70:
|
||||
fmt.Printf(" 中等\n")
|
||||
fallthrough
|
||||
case score >= 60:
|
||||
fmt.Printf(" 及格\n")
|
||||
default:
|
||||
fmt.Printf(" 不及格\n")
|
||||
}
|
||||
|
||||
// 另一个 fallthrough 示例
|
||||
level := 2
|
||||
fmt.Printf(" 用户等级 %d 的权限:\n", level)
|
||||
switch level {
|
||||
case 3:
|
||||
fmt.Printf(" - 管理员权限\n")
|
||||
fallthrough
|
||||
case 2:
|
||||
fmt.Printf(" - 编辑权限\n")
|
||||
fallthrough
|
||||
case 1:
|
||||
fmt.Printf(" - 查看权限\n")
|
||||
case 0:
|
||||
fmt.Printf(" - 无权限\n")
|
||||
}
|
||||
|
||||
// 注意事项
|
||||
fmt.Printf(" 注意: fallthrough 只能在 case 的最后一行使用\n")
|
||||
fmt.Printf(" 注意: fallthrough 会无条件执行下一个 case\n")
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateExpressionlessSwitch 演示无表达式 switch
|
||||
func demonstrateExpressionlessSwitch() {
|
||||
fmt.Println("4. 无表达式 switch:")
|
||||
|
||||
fmt.Printf(" 无表达式 switch 相当于 switch true,可以替代长的 if-else if 链\n")
|
||||
|
||||
// 年龄分组
|
||||
age := 25
|
||||
fmt.Printf(" 年龄 %d 岁: ", age)
|
||||
switch {
|
||||
case age < 13:
|
||||
fmt.Printf("儿童\n")
|
||||
case age < 20:
|
||||
fmt.Printf("青少年\n")
|
||||
case age < 60:
|
||||
fmt.Printf("成年人\n")
|
||||
default:
|
||||
fmt.Printf("老年人\n")
|
||||
}
|
||||
|
||||
// 温度判断
|
||||
temperature := 28
|
||||
fmt.Printf(" 温度 %d°C: ", temperature)
|
||||
switch {
|
||||
case temperature < 0:
|
||||
fmt.Printf("冰点以下\n")
|
||||
case temperature < 10:
|
||||
fmt.Printf("寒冷\n")
|
||||
case temperature < 20:
|
||||
fmt.Printf("凉爽\n")
|
||||
case temperature < 30:
|
||||
fmt.Printf("温暖\n")
|
||||
default:
|
||||
fmt.Printf("炎热\n")
|
||||
}
|
||||
|
||||
// 复杂条件
|
||||
hour := 14
|
||||
isWeekend := false
|
||||
fmt.Printf(" 时间 %d:00, 周末: %t - ", hour, isWeekend)
|
||||
switch {
|
||||
case hour < 6:
|
||||
fmt.Printf("深夜时间\n")
|
||||
case hour < 12 && !isWeekend:
|
||||
fmt.Printf("工作上午\n")
|
||||
case hour < 12 && isWeekend:
|
||||
fmt.Printf("周末上午\n")
|
||||
case hour < 18 && !isWeekend:
|
||||
fmt.Printf("工作下午\n")
|
||||
case hour < 18 && isWeekend:
|
||||
fmt.Printf("周末下午\n")
|
||||
case hour < 22:
|
||||
fmt.Printf("晚上时间\n")
|
||||
default:
|
||||
fmt.Printf("夜晚时间\n")
|
||||
}
|
||||
|
||||
// 数值范围判断
|
||||
value := 75
|
||||
fmt.Printf(" 数值 %d: ", value)
|
||||
switch {
|
||||
case value < 0:
|
||||
fmt.Printf("负数\n")
|
||||
case value == 0:
|
||||
fmt.Printf("零\n")
|
||||
case value <= 50:
|
||||
fmt.Printf("小数值 (1-50)\n")
|
||||
case value <= 100:
|
||||
fmt.Printf("中等数值 (51-100)\n")
|
||||
default:
|
||||
fmt.Printf("大数值 (>100)\n")
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateTypeSwitch 演示类型 switch
|
||||
func demonstrateTypeSwitch() {
|
||||
fmt.Println("5. 类型 switch:")
|
||||
|
||||
fmt.Printf(" 类型 switch 用于判断接口变量的实际类型\n")
|
||||
|
||||
// 定义不同类型的变量
|
||||
values := []interface{}{
|
||||
42,
|
||||
"hello",
|
||||
3.14,
|
||||
true,
|
||||
[]int{1, 2, 3},
|
||||
map[string]int{"a": 1},
|
||||
nil,
|
||||
}
|
||||
|
||||
for i, v := range values {
|
||||
fmt.Printf(" 值 %d: %v - ", i+1, v)
|
||||
switch t := v.(type) {
|
||||
case nil:
|
||||
fmt.Printf("nil 类型\n")
|
||||
case bool:
|
||||
fmt.Printf("布尔类型: %t\n", t)
|
||||
case int:
|
||||
fmt.Printf("整数类型: %d\n", t)
|
||||
case string:
|
||||
fmt.Printf("字符串类型: \"%s\" (长度: %d)\n", t, len(t))
|
||||
case float64:
|
||||
fmt.Printf("浮点类型: %.2f\n", t)
|
||||
case []int:
|
||||
fmt.Printf("整数切片: %v (长度: %d)\n", t, len(t))
|
||||
case map[string]int:
|
||||
fmt.Printf("字符串到整数的映射: %v\n", t)
|
||||
default:
|
||||
fmt.Printf("未知类型: %T\n", t)
|
||||
}
|
||||
}
|
||||
|
||||
// 类型 switch 的另一种用法
|
||||
fmt.Printf(" 处理不同类型的数据:\n")
|
||||
processValue(42)
|
||||
processValue("Go语言")
|
||||
processValue(3.14159)
|
||||
processValue([]string{"a", "b", "c"})
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateSwitchWithDeclaration 演示 switch 中的变量声明
|
||||
func demonstrateSwitchWithDeclaration() {
|
||||
fmt.Println("6. switch 中的变量声明:")
|
||||
|
||||
// 在 switch 中声明变量
|
||||
fmt.Printf(" 在 switch 中声明变量:\n")
|
||||
switch num := rand.Intn(10); {
|
||||
case num < 3:
|
||||
fmt.Printf(" 随机数 %d < 3,小数值\n", num)
|
||||
case num < 7:
|
||||
fmt.Printf(" 随机数 %d 在 3-6 之间,中等数值\n", num)
|
||||
default:
|
||||
fmt.Printf(" 随机数 %d >= 7,大数值\n", num)
|
||||
}
|
||||
|
||||
// 计算并判断
|
||||
switch result := calculateGrade(85); result {
|
||||
case "A":
|
||||
fmt.Printf(" 成绩优秀: %s\n", result)
|
||||
case "B":
|
||||
fmt.Printf(" 成绩良好: %s\n", result)
|
||||
case "C":
|
||||
fmt.Printf(" 成绩中等: %s\n", result)
|
||||
default:
|
||||
fmt.Printf(" 成绩: %s\n", result)
|
||||
}
|
||||
|
||||
// 字符串处理
|
||||
switch length := len("Hello, World!"); {
|
||||
case length < 5:
|
||||
fmt.Printf(" 字符串长度 %d,较短\n", length)
|
||||
case length < 10:
|
||||
fmt.Printf(" 字符串长度 %d,中等\n", length)
|
||||
default:
|
||||
fmt.Printf(" 字符串长度 %d,较长\n", length)
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstratePracticalExamples 演示实际应用示例
|
||||
func demonstratePracticalExamples() {
|
||||
fmt.Println("7. 实际应用示例:")
|
||||
|
||||
// 示例1: HTTP 请求处理
|
||||
fmt.Printf(" 示例1 - HTTP 请求处理:\n")
|
||||
method := "POST"
|
||||
path := "/api/users"
|
||||
|
||||
switch method {
|
||||
case "GET":
|
||||
fmt.Printf(" 处理 GET 请求: 获取资源 %s\n", path)
|
||||
case "POST":
|
||||
fmt.Printf(" 处理 POST 请求: 创建资源 %s\n", path)
|
||||
case "PUT":
|
||||
fmt.Printf(" 处理 PUT 请求: 更新资源 %s\n", path)
|
||||
case "DELETE":
|
||||
fmt.Printf(" 处理 DELETE 请求: 删除资源 %s\n", path)
|
||||
default:
|
||||
fmt.Printf(" 不支持的 HTTP 方法: %s\n", method)
|
||||
}
|
||||
|
||||
// 示例2: 文件扩展名处理
|
||||
fmt.Printf(" 示例2 - 文件类型判断:\n")
|
||||
filename := "document.pdf"
|
||||
var fileType string
|
||||
|
||||
switch {
|
||||
case hasExtension(filename, ".txt", ".md", ".doc", ".docx"):
|
||||
fileType = "文档文件"
|
||||
case hasExtension(filename, ".jpg", ".png", ".gif", ".bmp"):
|
||||
fileType = "图片文件"
|
||||
case hasExtension(filename, ".mp4", ".avi", ".mov", ".wmv"):
|
||||
fileType = "视频文件"
|
||||
case hasExtension(filename, ".mp3", ".wav", ".flac", ".aac"):
|
||||
fileType = "音频文件"
|
||||
case hasExtension(filename, ".pdf"):
|
||||
fileType = "PDF文件"
|
||||
case hasExtension(filename, ".zip", ".rar", ".7z", ".tar"):
|
||||
fileType = "压缩文件"
|
||||
default:
|
||||
fileType = "未知文件类型"
|
||||
}
|
||||
|
||||
fmt.Printf(" 文件 \"%s\" 是 %s\n", filename, fileType)
|
||||
|
||||
// 示例3: 游戏状态机
|
||||
fmt.Printf(" 示例3 - 游戏状态处理:\n")
|
||||
gameState := "playing"
|
||||
playerHealth := 30
|
||||
|
||||
switch gameState {
|
||||
case "menu":
|
||||
fmt.Printf(" 显示主菜单\n")
|
||||
case "playing":
|
||||
fmt.Printf(" 游戏进行中\n")
|
||||
switch {
|
||||
case playerHealth <= 0:
|
||||
fmt.Printf(" 玩家死亡,游戏结束\n")
|
||||
case playerHealth < 20:
|
||||
fmt.Printf(" 玩家生命值低 (%d),危险状态\n", playerHealth)
|
||||
case playerHealth < 50:
|
||||
fmt.Printf(" 玩家生命值中等 (%d),注意安全\n", playerHealth)
|
||||
default:
|
||||
fmt.Printf(" 玩家状态良好 (%d)\n", playerHealth)
|
||||
}
|
||||
case "paused":
|
||||
fmt.Printf(" 游戏暂停\n")
|
||||
case "gameover":
|
||||
fmt.Printf(" 游戏结束\n")
|
||||
default:
|
||||
fmt.Printf(" 未知游戏状态: %s\n", gameState)
|
||||
}
|
||||
|
||||
// 示例4: 错误码处理
|
||||
fmt.Printf(" 示例4 - 错误码处理:\n")
|
||||
errorCode := 1001
|
||||
|
||||
switch errorCode {
|
||||
case 0:
|
||||
fmt.Printf(" 操作成功\n")
|
||||
case 1000, 1001, 1002:
|
||||
fmt.Printf(" 用户相关错误 (错误码: %d)\n", errorCode)
|
||||
switch errorCode {
|
||||
case 1000:
|
||||
fmt.Printf(" 用户不存在\n")
|
||||
case 1001:
|
||||
fmt.Printf(" 密码错误\n")
|
||||
case 1002:
|
||||
fmt.Printf(" 账户被锁定\n")
|
||||
}
|
||||
case 2000, 2001, 2002:
|
||||
fmt.Printf(" 权限相关错误 (错误码: %d)\n", errorCode)
|
||||
case 3000, 3001, 3002:
|
||||
fmt.Printf(" 数据相关错误 (错误码: %d)\n", errorCode)
|
||||
default:
|
||||
fmt.Printf(" 未知错误 (错误码: %d)\n", errorCode)
|
||||
}
|
||||
|
||||
// 示例5: 配置解析
|
||||
fmt.Printf(" 示例5 - 配置解析:\n")
|
||||
config := map[string]interface{}{
|
||||
"debug": true,
|
||||
"port": 8080,
|
||||
"database": "mysql",
|
||||
"timeout": 30.5,
|
||||
}
|
||||
|
||||
for key, value := range config {
|
||||
fmt.Printf(" 配置项 %s: ", key)
|
||||
switch v := value.(type) {
|
||||
case bool:
|
||||
if v {
|
||||
fmt.Printf("启用\n")
|
||||
} else {
|
||||
fmt.Printf("禁用\n")
|
||||
}
|
||||
case int:
|
||||
fmt.Printf("数值 %d\n", v)
|
||||
case float64:
|
||||
fmt.Printf("浮点数 %.1f\n", v)
|
||||
case string:
|
||||
fmt.Printf("字符串 \"%s\"\n", v)
|
||||
default:
|
||||
fmt.Printf("未知类型 %T\n", v)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// 辅助函数
|
||||
func processValue(v interface{}) {
|
||||
switch val := v.(type) {
|
||||
case int:
|
||||
fmt.Printf(" 处理整数: %d,平方: %d\n", val, val*val)
|
||||
case string:
|
||||
fmt.Printf(" 处理字符串: \"%s\",长度: %d\n", val, len(val))
|
||||
case float64:
|
||||
fmt.Printf(" 处理浮点数: %.3f,四舍五入: %.0f\n", val, val)
|
||||
case []string:
|
||||
fmt.Printf(" 处理字符串切片: %v,元素个数: %d\n", val, len(val))
|
||||
default:
|
||||
fmt.Printf(" 无法处理的类型: %T\n", val)
|
||||
}
|
||||
}
|
||||
|
||||
func calculateGrade(score int) string {
|
||||
switch {
|
||||
case score >= 90:
|
||||
return "A"
|
||||
case score >= 80:
|
||||
return "B"
|
||||
case score >= 70:
|
||||
return "C"
|
||||
case score >= 60:
|
||||
return "D"
|
||||
default:
|
||||
return "F"
|
||||
}
|
||||
}
|
||||
|
||||
func hasExtension(filename string, extensions ...string) bool {
|
||||
for _, ext := range extensions {
|
||||
if len(filename) >= len(ext) &&
|
||||
filename[len(filename)-len(ext):] == ext {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func init() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
}
|
||||
|
||||
/*
|
||||
运行这个程序:
|
||||
go run 02-switch.go
|
||||
|
||||
学习要点:
|
||||
1. Go 的 switch 语句自动 break,不需要显式写 break
|
||||
2. case 可以包含多个值,用逗号分隔
|
||||
3. fallthrough 关键字可以让程序继续执行下一个 case
|
||||
4. 无表达式 switch 相当于 switch true,可以替代长的 if-else if 链
|
||||
5. 类型 switch 用于判断接口变量的实际类型
|
||||
6. 可以在 switch 语句中声明变量
|
||||
|
||||
Go switch 的优势:
|
||||
1. 比长的 if-else if 链更清晰
|
||||
2. 自动 break 避免了忘记 break 的错误
|
||||
3. 支持多值 case,代码更简洁
|
||||
4. 类型 switch 提供了强大的类型判断能力
|
||||
5. 无表达式 switch 提供了灵活的条件判断
|
||||
|
||||
使用建议:
|
||||
1. 当有多个固定值需要判断时,优先使用 switch
|
||||
2. 当条件复杂时,使用无表达式 switch
|
||||
3. 处理接口类型时,使用类型 switch
|
||||
4. 谨慎使用 fallthrough,确保逻辑正确
|
||||
5. 合理使用 default 分支处理异常情况
|
||||
|
||||
常见应用场景:
|
||||
1. 状态机实现
|
||||
2. 错误码处理
|
||||
3. 文件类型判断
|
||||
4. HTTP 请求路由
|
||||
5. 配置解析
|
||||
6. 类型判断和处理
|
||||
*/
|
633
golang-learning/02-control-flow/03-for-loops.go
Normal file
633
golang-learning/02-control-flow/03-for-loops.go
Normal file
@@ -0,0 +1,633 @@
|
||||
/*
|
||||
03-for-loops.go - Go 语言 for 循环详解
|
||||
|
||||
学习目标:
|
||||
1. 掌握 for 循环的各种形式
|
||||
2. 理解 break 和 continue 的使用
|
||||
3. 学会使用标签控制嵌套循环
|
||||
4. 了解无限循环的写法
|
||||
5. 掌握循环的实际应用场景
|
||||
|
||||
知识点:
|
||||
- 传统 for 循环
|
||||
- while 风格的 for 循环
|
||||
- 无限循环
|
||||
- break 和 continue
|
||||
- 标签 (label)
|
||||
- 嵌套循环
|
||||
- 循环优化技巧
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== Go 语言 for 循环详解 ===\n")
|
||||
|
||||
// 演示传统 for 循环
|
||||
demonstrateTraditionalFor()
|
||||
|
||||
// 演示 while 风格的 for 循环
|
||||
demonstrateWhileStyleFor()
|
||||
|
||||
// 演示无限循环
|
||||
demonstrateInfiniteLoop()
|
||||
|
||||
// 演示 break 和 continue
|
||||
demonstrateBreakContinue()
|
||||
|
||||
// 演示嵌套循环和标签
|
||||
demonstrateNestedLoopsAndLabels()
|
||||
|
||||
// 演示循环的实际应用
|
||||
demonstratePracticalExamples()
|
||||
|
||||
// 演示循环优化技巧
|
||||
demonstrateOptimizationTips()
|
||||
}
|
||||
|
||||
// demonstrateTraditionalFor 演示传统 for 循环
|
||||
func demonstrateTraditionalFor() {
|
||||
fmt.Println("1. 传统 for 循环:")
|
||||
|
||||
// 基本的 for 循环
|
||||
fmt.Printf(" 基本 for 循环 (0-4):\n")
|
||||
for i := 0; i < 5; i++ {
|
||||
fmt.Printf(" i = %d\n", i)
|
||||
}
|
||||
|
||||
// 倒序循环
|
||||
fmt.Printf(" 倒序循环 (5-1):\n")
|
||||
for i := 5; i > 0; i-- {
|
||||
fmt.Printf(" i = %d\n", i)
|
||||
}
|
||||
|
||||
// 步长为 2 的循环
|
||||
fmt.Printf(" 步长为 2 的循环:\n")
|
||||
for i := 0; i <= 10; i += 2 {
|
||||
fmt.Printf(" i = %d\n", i)
|
||||
}
|
||||
|
||||
// 多个变量的循环
|
||||
fmt.Printf(" 多变量循环:\n")
|
||||
for i, j := 0, 10; i < j; i, j = i+1, j-1 {
|
||||
fmt.Printf(" i = %d, j = %d\n", i, j)
|
||||
}
|
||||
|
||||
// 计算累加和
|
||||
sum := 0
|
||||
for i := 1; i <= 10; i++ {
|
||||
sum += i
|
||||
}
|
||||
fmt.Printf(" 1到10的累加和: %d\n", sum)
|
||||
|
||||
// 计算阶乘
|
||||
factorial := 1
|
||||
n := 5
|
||||
for i := 1; i <= n; i++ {
|
||||
factorial *= i
|
||||
}
|
||||
fmt.Printf(" %d的阶乘: %d\n", n, factorial)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateWhileStyleFor 演示 while 风格的 for 循环
|
||||
func demonstrateWhileStyleFor() {
|
||||
fmt.Println("2. while 风格的 for 循环:")
|
||||
|
||||
fmt.Printf(" Go 没有 while 关键字,使用 for 代替\n")
|
||||
|
||||
// 模拟 while 循环
|
||||
fmt.Printf(" 模拟 while 循环:\n")
|
||||
count := 0
|
||||
for count < 5 {
|
||||
fmt.Printf(" count = %d\n", count)
|
||||
count++
|
||||
}
|
||||
|
||||
// 条件判断循环
|
||||
fmt.Printf(" 条件判断循环 (猜数字):\n")
|
||||
target := 7
|
||||
guess := 1
|
||||
attempts := 0
|
||||
|
||||
for guess != target {
|
||||
attempts++
|
||||
fmt.Printf(" 第 %d 次猜测: %d", attempts, guess)
|
||||
if guess < target {
|
||||
fmt.Printf(" (太小了)\n")
|
||||
guess += 2
|
||||
} else {
|
||||
fmt.Printf(" (太大了)\n")
|
||||
guess--
|
||||
}
|
||||
}
|
||||
fmt.Printf(" 恭喜!第 %d 次猜中了: %d\n", attempts+1, guess)
|
||||
|
||||
// 读取用户输入直到满足条件
|
||||
fmt.Printf(" 模拟输入验证:\n")
|
||||
password := ""
|
||||
attempts = 0
|
||||
correctPassword := "123456"
|
||||
|
||||
// 模拟用户输入
|
||||
inputs := []string{"111", "222", "123456"}
|
||||
|
||||
for password != correctPassword && attempts < 3 {
|
||||
password = inputs[attempts] // 模拟用户输入
|
||||
attempts++
|
||||
fmt.Printf(" 第 %d 次输入密码: %s", attempts, password)
|
||||
if password == correctPassword {
|
||||
fmt.Printf(" (正确)\n")
|
||||
} else {
|
||||
fmt.Printf(" (错误)\n")
|
||||
}
|
||||
}
|
||||
|
||||
if password == correctPassword {
|
||||
fmt.Printf(" 登录成功!\n")
|
||||
} else {
|
||||
fmt.Printf(" 登录失败,超过最大尝试次数\n")
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateInfiniteLoop 演示无限循环
|
||||
func demonstrateInfiniteLoop() {
|
||||
fmt.Println("3. 无限循环:")
|
||||
|
||||
fmt.Printf(" 无限循环的写法: for { ... }\n")
|
||||
fmt.Printf(" 通常配合 break 使用\n")
|
||||
|
||||
// 无限循环示例1: 服务器主循环模拟
|
||||
fmt.Printf(" 示例1 - 服务器主循环模拟:\n")
|
||||
requestCount := 0
|
||||
for {
|
||||
requestCount++
|
||||
fmt.Printf(" 处理第 %d 个请求\n", requestCount)
|
||||
|
||||
// 模拟处理请求
|
||||
if requestCount >= 3 {
|
||||
fmt.Printf(" 服务器关闭\n")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 无限循环示例2: 菜单系统
|
||||
fmt.Printf(" 示例2 - 菜单系统模拟:\n")
|
||||
menuOptions := []string{"查看余额", "转账", "退出"}
|
||||
choice := 0
|
||||
|
||||
for {
|
||||
fmt.Printf(" 请选择操作:\n")
|
||||
for i, option := range menuOptions {
|
||||
fmt.Printf(" %d. %s\n", i+1, option)
|
||||
}
|
||||
|
||||
// 模拟用户选择
|
||||
choice = (choice % 3) + 1
|
||||
fmt.Printf(" 用户选择: %d\n", choice)
|
||||
|
||||
switch choice {
|
||||
case 1:
|
||||
fmt.Printf(" 当前余额: 1000元\n")
|
||||
case 2:
|
||||
fmt.Printf(" 转账功能暂未开放\n")
|
||||
case 3:
|
||||
fmt.Printf(" 谢谢使用,再见!\n")
|
||||
return // 或者使用 break
|
||||
}
|
||||
|
||||
// 为了演示,只循环一次
|
||||
break
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateBreakContinue 演示 break 和 continue
|
||||
func demonstrateBreakContinue() {
|
||||
fmt.Println("4. break 和 continue:")
|
||||
|
||||
// break 示例
|
||||
fmt.Printf(" break - 跳出循环:\n")
|
||||
for i := 0; i < 10; i++ {
|
||||
if i == 5 {
|
||||
fmt.Printf(" 遇到 %d,跳出循环\n", i)
|
||||
break
|
||||
}
|
||||
fmt.Printf(" i = %d\n", i)
|
||||
}
|
||||
|
||||
// continue 示例
|
||||
fmt.Printf(" continue - 跳过当前迭代:\n")
|
||||
for i := 0; i < 10; i++ {
|
||||
if i%2 == 0 {
|
||||
continue // 跳过偶数
|
||||
}
|
||||
fmt.Printf(" 奇数: %d\n", i)
|
||||
}
|
||||
|
||||
// 实际应用:处理数据时跳过无效值
|
||||
fmt.Printf(" 实际应用 - 处理数据跳过无效值:\n")
|
||||
data := []int{1, -2, 3, 0, 5, -6, 7, 8, 0, 9}
|
||||
sum := 0
|
||||
validCount := 0
|
||||
|
||||
for i, value := range data {
|
||||
if value <= 0 {
|
||||
fmt.Printf(" 跳过无效值 data[%d] = %d\n", i, value)
|
||||
continue
|
||||
}
|
||||
sum += value
|
||||
validCount++
|
||||
fmt.Printf(" 处理有效值 data[%d] = %d\n", i, value)
|
||||
}
|
||||
|
||||
fmt.Printf(" 有效数据个数: %d,总和: %d,平均值: %.2f\n",
|
||||
validCount, sum, float64(sum)/float64(validCount))
|
||||
|
||||
// 查找第一个满足条件的元素
|
||||
fmt.Printf(" 查找第一个大于 50 的数:\n")
|
||||
numbers := []int{10, 25, 30, 55, 60, 75}
|
||||
found := false
|
||||
|
||||
for i, num := range numbers {
|
||||
fmt.Printf(" 检查 numbers[%d] = %d\n", i, num)
|
||||
if num > 50 {
|
||||
fmt.Printf(" 找到第一个大于 50 的数: %d\n", num)
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
fmt.Printf(" 没有找到大于 50 的数\n")
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateNestedLoopsAndLabels 演示嵌套循环和标签
|
||||
func demonstrateNestedLoopsAndLabels() {
|
||||
fmt.Println("5. 嵌套循环和标签:")
|
||||
|
||||
// 基本嵌套循环
|
||||
fmt.Printf(" 基本嵌套循环 - 乘法表:\n")
|
||||
for i := 1; i <= 3; i++ {
|
||||
for j := 1; j <= 3; j++ {
|
||||
fmt.Printf(" %d × %d = %d\n", i, j, i*j)
|
||||
}
|
||||
}
|
||||
|
||||
// 使用标签控制嵌套循环
|
||||
fmt.Printf(" 使用标签控制嵌套循环:\n")
|
||||
|
||||
outer:
|
||||
for i := 1; i <= 3; i++ {
|
||||
for j := 1; j <= 3; j++ {
|
||||
fmt.Printf(" i=%d, j=%d\n", i, j)
|
||||
if i == 2 && j == 2 {
|
||||
fmt.Printf(" 在 i=2, j=2 时跳出外层循环\n")
|
||||
break outer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 标签 continue 示例
|
||||
fmt.Printf(" 标签 continue 示例:\n")
|
||||
|
||||
outerContinue:
|
||||
for i := 1; i <= 3; i++ {
|
||||
fmt.Printf(" 外层循环 i = %d\n", i)
|
||||
for j := 1; j <= 3; j++ {
|
||||
if i == 2 && j == 2 {
|
||||
fmt.Printf(" 在 i=2, j=2 时跳过外层循环的当前迭代\n")
|
||||
continue outerContinue
|
||||
}
|
||||
fmt.Printf(" 内层循环 j = %d\n", j)
|
||||
}
|
||||
fmt.Printf(" 外层循环 i = %d 结束\n", i)
|
||||
}
|
||||
|
||||
// 矩阵搜索示例
|
||||
fmt.Printf(" 矩阵搜索示例:\n")
|
||||
matrix := [][]int{
|
||||
{1, 2, 3},
|
||||
{4, 5, 6},
|
||||
{7, 8, 9},
|
||||
}
|
||||
target := 5
|
||||
found := false
|
||||
|
||||
search:
|
||||
for i := 0; i < len(matrix); i++ {
|
||||
for j := 0; j < len(matrix[i]); j++ {
|
||||
fmt.Printf(" 检查 matrix[%d][%d] = %d\n", i, j, matrix[i][j])
|
||||
if matrix[i][j] == target {
|
||||
fmt.Printf(" 找到目标值 %d 在位置 [%d][%d]\n", target, i, j)
|
||||
found = true
|
||||
break search
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
fmt.Printf(" 未找到目标值 %d\n", target)
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstratePracticalExamples 演示循环的实际应用
|
||||
func demonstratePracticalExamples() {
|
||||
fmt.Println("6. 循环的实际应用:")
|
||||
|
||||
// 示例1: 数组/切片处理
|
||||
fmt.Printf(" 示例1 - 数组处理:\n")
|
||||
scores := []int{85, 92, 78, 96, 88, 73, 91}
|
||||
|
||||
// 计算平均分
|
||||
total := 0
|
||||
for _, score := range scores {
|
||||
total += score
|
||||
}
|
||||
average := float64(total) / float64(len(scores))
|
||||
fmt.Printf(" 平均分: %.2f\n", average)
|
||||
|
||||
// 找出最高分和最低分
|
||||
maxScore, minScore := scores[0], scores[0]
|
||||
for _, score := range scores {
|
||||
if score > maxScore {
|
||||
maxScore = score
|
||||
}
|
||||
if score < minScore {
|
||||
minScore = score
|
||||
}
|
||||
}
|
||||
fmt.Printf(" 最高分: %d,最低分: %d\n", maxScore, minScore)
|
||||
|
||||
// 统计及格人数
|
||||
passCount := 0
|
||||
for _, score := range scores {
|
||||
if score >= 80 {
|
||||
passCount++
|
||||
}
|
||||
}
|
||||
fmt.Printf(" 及格人数: %d/%d\n", passCount, len(scores))
|
||||
|
||||
// 示例2: 字符串处理
|
||||
fmt.Printf(" 示例2 - 字符串处理:\n")
|
||||
text := "Hello, 世界! 123"
|
||||
|
||||
// 统计字符类型
|
||||
letters, digits, others := 0, 0, 0
|
||||
for _, char := range text {
|
||||
switch {
|
||||
case (char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') || char > 127:
|
||||
letters++
|
||||
case char >= '0' && char <= '9':
|
||||
digits++
|
||||
default:
|
||||
others++
|
||||
}
|
||||
}
|
||||
fmt.Printf(" 字符串: \"%s\"\n", text)
|
||||
fmt.Printf(" 字母: %d,数字: %d,其他: %d\n", letters, digits, others)
|
||||
|
||||
// 示例3: 数学计算
|
||||
fmt.Printf(" 示例3 - 数学计算 (斐波那契数列):\n")
|
||||
n := 10
|
||||
fmt.Printf(" 前 %d 个斐波那契数:\n", n)
|
||||
|
||||
a, b := 0, 1
|
||||
for i := 0; i < n; i++ {
|
||||
fmt.Printf(" F(%d) = %d\n", i, a)
|
||||
a, b = b, a+b
|
||||
}
|
||||
|
||||
// 示例4: 模拟游戏
|
||||
fmt.Printf(" 示例4 - 简单猜数字游戏:\n")
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
secretNumber := rand.Intn(10) + 1
|
||||
maxAttempts := 3
|
||||
|
||||
// 模拟玩家猜测
|
||||
guesses := []int{5, 8, secretNumber}
|
||||
|
||||
for attempt := 1; attempt <= maxAttempts; attempt++ {
|
||||
guess := guesses[attempt-1] // 模拟用户输入
|
||||
fmt.Printf(" 第 %d 次猜测: %d", attempt, guess)
|
||||
|
||||
if guess == secretNumber {
|
||||
fmt.Printf(" - 恭喜你猜对了!\n")
|
||||
break
|
||||
} else if guess < secretNumber {
|
||||
fmt.Printf(" - 太小了\n")
|
||||
} else {
|
||||
fmt.Printf(" - 太大了\n")
|
||||
}
|
||||
|
||||
if attempt == maxAttempts {
|
||||
fmt.Printf(" 游戏结束!正确答案是: %d\n", secretNumber)
|
||||
}
|
||||
}
|
||||
|
||||
// 示例5: 数据验证
|
||||
fmt.Printf(" 示例5 - 批量数据验证:\n")
|
||||
emails := []string{
|
||||
"user@example.com",
|
||||
"invalid-email",
|
||||
"test@domain.org",
|
||||
"@invalid.com",
|
||||
"valid@test.net",
|
||||
}
|
||||
|
||||
validEmails := 0
|
||||
for i, email := range emails {
|
||||
isValid := validateEmail(email)
|
||||
fmt.Printf(" 邮箱 %d: %-20s - ", i+1, email)
|
||||
if isValid {
|
||||
fmt.Printf("有效\n")
|
||||
validEmails++
|
||||
} else {
|
||||
fmt.Printf("无效\n")
|
||||
}
|
||||
}
|
||||
fmt.Printf(" 有效邮箱数量: %d/%d\n", validEmails, len(emails))
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateOptimizationTips 演示循环优化技巧
|
||||
func demonstrateOptimizationTips() {
|
||||
fmt.Println("7. 循环优化技巧:")
|
||||
|
||||
// 技巧1: 减少重复计算
|
||||
fmt.Printf(" 技巧1 - 减少重复计算:\n")
|
||||
data := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
|
||||
// 不好的写法:每次都计算 len(data)
|
||||
fmt.Printf(" 不推荐的写法 (每次计算长度):\n")
|
||||
for i := 0; i < len(data); i++ {
|
||||
// len(data) 在每次迭代时都会被调用
|
||||
fmt.Printf(" data[%d] = %d\n", i, data[i])
|
||||
if i >= 2 { // 为了演示,只显示前几个
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 好的写法:预先计算长度
|
||||
fmt.Printf(" 推荐的写法 (预先计算长度):\n")
|
||||
length := len(data)
|
||||
for i := 0; i < length; i++ {
|
||||
fmt.Printf(" data[%d] = %d\n", i, data[i])
|
||||
if i >= 2 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 技巧2: 使用 range 遍历
|
||||
fmt.Printf(" 技巧2 - 使用 range 遍历 (更简洁):\n")
|
||||
for i, value := range data {
|
||||
fmt.Printf(" data[%d] = %d\n", i, value)
|
||||
if i >= 2 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 技巧3: 提前退出
|
||||
fmt.Printf(" 技巧3 - 提前退出优化:\n")
|
||||
numbers := []int{2, 4, 6, 7, 8, 10, 12}
|
||||
|
||||
// 查找第一个奇数
|
||||
for i, num := range numbers {
|
||||
fmt.Printf(" 检查 numbers[%d] = %d", i, num)
|
||||
if num%2 == 1 {
|
||||
fmt.Printf(" - 找到第一个奇数: %d\n", num)
|
||||
break // 找到后立即退出,不继续遍历
|
||||
}
|
||||
fmt.Printf(" - 偶数,继续查找\n")
|
||||
}
|
||||
|
||||
// 技巧4: 批量处理
|
||||
fmt.Printf(" 技巧4 - 批量处理:\n")
|
||||
largeData := make([]int, 20)
|
||||
for i := range largeData {
|
||||
largeData[i] = i + 1
|
||||
}
|
||||
|
||||
batchSize := 5
|
||||
fmt.Printf(" 批量处理数据 (批次大小: %d):\n", batchSize)
|
||||
|
||||
for i := 0; i < len(largeData); i += batchSize {
|
||||
end := i + batchSize
|
||||
if end > len(largeData) {
|
||||
end = len(largeData)
|
||||
}
|
||||
|
||||
batch := largeData[i:end]
|
||||
fmt.Printf(" 处理批次 %d-%d: %v\n", i, end-1, batch)
|
||||
|
||||
// 模拟批量处理
|
||||
batchSum := 0
|
||||
for _, value := range batch {
|
||||
batchSum += value
|
||||
}
|
||||
fmt.Printf(" 批次总和: %d\n", batchSum)
|
||||
}
|
||||
|
||||
// 技巧5: 避免不必要的操作
|
||||
fmt.Printf(" 技巧5 - 避免不必要的操作:\n")
|
||||
matrix2 := [][]int{
|
||||
{1, 2, 3, 4},
|
||||
{5, 6, 7, 8},
|
||||
{9, 10, 11, 12},
|
||||
}
|
||||
|
||||
// 只处理对角线元素
|
||||
fmt.Printf(" 只处理矩阵对角线元素:\n")
|
||||
for i := 0; i < len(matrix2) && i < len(matrix2[0]); i++ {
|
||||
fmt.Printf(" 对角线元素 [%d][%d] = %d\n", i, i, matrix2[i][i])
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// 辅助函数
|
||||
func validateEmail(email string) bool {
|
||||
// 简单的邮箱验证(实际应用中应该使用正则表达式)
|
||||
if len(email) < 5 {
|
||||
return false
|
||||
}
|
||||
|
||||
hasAt := false
|
||||
hasDot := false
|
||||
atPos := -1
|
||||
|
||||
for i, char := range email {
|
||||
if char == '@' {
|
||||
if hasAt || i == 0 || i == len(email)-1 {
|
||||
return false
|
||||
}
|
||||
hasAt = true
|
||||
atPos = i
|
||||
} else if char == '.' && hasAt && i > atPos+1 && i < len(email)-1 {
|
||||
hasDot = true
|
||||
}
|
||||
}
|
||||
|
||||
return hasAt && hasDot
|
||||
}
|
||||
|
||||
/*
|
||||
运行这个程序:
|
||||
go run 03-for-loops.go
|
||||
|
||||
学习要点:
|
||||
1. Go 只有 for 循环,没有 while 和 do-while
|
||||
2. for 循环有三种形式:传统形式、while 形式、无限循环形式
|
||||
3. break 用于跳出循环,continue 用于跳过当前迭代
|
||||
4. 标签可以用来控制嵌套循环的跳转
|
||||
5. range 关键字提供了遍历数组、切片、字符串等的便捷方式
|
||||
|
||||
for 循环的三种形式:
|
||||
1. for init; condition; post { ... } // 传统形式
|
||||
2. for condition { ... } // while 形式
|
||||
3. for { ... } // 无限循环
|
||||
|
||||
循环控制:
|
||||
1. break: 跳出当前循环
|
||||
2. continue: 跳过当前迭代,继续下一次迭代
|
||||
3. 标签: 可以跳出或跳过指定的外层循环
|
||||
|
||||
优化建议:
|
||||
1. 减少循环内的重复计算
|
||||
2. 使用 range 遍历集合类型
|
||||
3. 适当使用 break 提前退出
|
||||
4. 考虑批量处理大量数据
|
||||
5. 避免不必要的嵌套循环
|
||||
|
||||
常见应用场景:
|
||||
1. 数组/切片遍历和处理
|
||||
2. 数值计算(累加、阶乘等)
|
||||
3. 字符串处理
|
||||
4. 数据验证和过滤
|
||||
5. 算法实现
|
||||
6. 游戏循环
|
||||
7. 服务器主循环
|
||||
|
||||
注意事项:
|
||||
1. 避免无限循环(除非有明确的退出条件)
|
||||
2. 注意循环变量的作用域
|
||||
3. 在嵌套循环中正确使用标签
|
||||
4. 考虑循环的时间复杂度
|
||||
5. 合理使用 break 和 continue
|
||||
*/
|
698
golang-learning/02-control-flow/04-range.go
Normal file
698
golang-learning/02-control-flow/04-range.go
Normal file
@@ -0,0 +1,698 @@
|
||||
/*
|
||||
04-range.go - Go 语言 range 关键字详解
|
||||
|
||||
学习目标:
|
||||
1. 掌握 range 的基本用法
|
||||
2. 理解 range 在不同数据类型上的应用
|
||||
3. 学会处理 range 返回的索引和值
|
||||
4. 了解 range 的性能特点
|
||||
5. 掌握 range 的实际应用场景
|
||||
|
||||
知识点:
|
||||
- range 遍历数组和切片
|
||||
- range 遍历字符串
|
||||
- range 遍历映射 (map)
|
||||
- range 遍历通道 (channel)
|
||||
- range 的值拷贝特性
|
||||
- 忽略索引或值的技巧
|
||||
- range 的性能考虑
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== Go 语言 range 关键字详解 ===\n")
|
||||
|
||||
// 演示 range 遍历数组和切片
|
||||
demonstrateRangeArraySlice()
|
||||
|
||||
// 演示 range 遍历字符串
|
||||
demonstrateRangeString()
|
||||
|
||||
// 演示 range 遍历映射
|
||||
demonstrateRangeMap()
|
||||
|
||||
// 演示 range 遍历通道
|
||||
demonstrateRangeChannel()
|
||||
|
||||
// 演示 range 的值拷贝特性
|
||||
demonstrateRangeValueCopy()
|
||||
|
||||
// 演示忽略索引或值
|
||||
demonstrateIgnoreIndexValue()
|
||||
|
||||
// 演示 range 的实际应用
|
||||
demonstratePracticalExamples()
|
||||
|
||||
// 演示 range 的性能考虑
|
||||
demonstratePerformanceConsiderations()
|
||||
}
|
||||
|
||||
// demonstrateRangeArraySlice 演示 range 遍历数组和切片
|
||||
func demonstrateRangeArraySlice() {
|
||||
fmt.Println("1. range 遍历数组和切片:")
|
||||
|
||||
// 遍历数组
|
||||
fmt.Printf(" 遍历数组:\n")
|
||||
arr := [5]int{10, 20, 30, 40, 50}
|
||||
|
||||
for index, value := range arr {
|
||||
fmt.Printf(" arr[%d] = %d\n", index, value)
|
||||
}
|
||||
|
||||
// 遍历切片
|
||||
fmt.Printf(" 遍历切片:\n")
|
||||
slice := []string{"Go", "Python", "Java", "JavaScript"}
|
||||
|
||||
for i, lang := range slice {
|
||||
fmt.Printf(" 语言 %d: %s\n", i+1, lang)
|
||||
}
|
||||
|
||||
// 遍历空切片
|
||||
fmt.Printf(" 遍历空切片:\n")
|
||||
var emptySlice []int
|
||||
count := 0
|
||||
for range emptySlice {
|
||||
count++
|
||||
}
|
||||
fmt.Printf(" 空切片遍历次数: %d\n", count)
|
||||
|
||||
// 遍历 nil 切片
|
||||
fmt.Printf(" 遍历 nil 切片:\n")
|
||||
var nilSlice []int = nil
|
||||
count = 0
|
||||
for range nilSlice {
|
||||
count++
|
||||
}
|
||||
fmt.Printf(" nil 切片遍历次数: %d\n", count)
|
||||
|
||||
// 多维切片遍历
|
||||
fmt.Printf(" 遍历二维切片:\n")
|
||||
matrix := [][]int{
|
||||
{1, 2, 3},
|
||||
{4, 5, 6},
|
||||
{7, 8, 9},
|
||||
}
|
||||
|
||||
for i, row := range matrix {
|
||||
for j, value := range row {
|
||||
fmt.Printf(" matrix[%d][%d] = %d\n", i, j, value)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateRangeString 演示 range 遍历字符串
|
||||
func demonstrateRangeString() {
|
||||
fmt.Println("2. range 遍历字符串:")
|
||||
|
||||
// 基本字符串遍历
|
||||
fmt.Printf(" 遍历 ASCII 字符串:\n")
|
||||
str1 := "Hello"
|
||||
|
||||
for index, char := range str1 {
|
||||
fmt.Printf(" str1[%d] = '%c' (Unicode: %d)\n", index, char, char)
|
||||
}
|
||||
|
||||
// 遍历包含中文的字符串
|
||||
fmt.Printf(" 遍历包含中文的字符串:\n")
|
||||
str2 := "Hello世界"
|
||||
|
||||
for index, char := range str2 {
|
||||
fmt.Printf(" 位置 %d: '%c' (Unicode: %d)\n", index, char, char)
|
||||
}
|
||||
|
||||
// 注意:index 是字节位置,不是字符位置
|
||||
fmt.Printf(" 注意: range 返回的索引是字节位置,不是字符位置\n")
|
||||
|
||||
// 字符串长度对比
|
||||
fmt.Printf(" 字符串长度对比:\n")
|
||||
fmt.Printf(" 字节长度 len(\"%s\"): %d\n", str2, len(str2))
|
||||
fmt.Printf(" 字符长度 utf8.RuneCountInString(\"%s\"): %d\n",
|
||||
str2, utf8.RuneCountInString(str2))
|
||||
|
||||
// 遍历字符串的字节
|
||||
fmt.Printf(" 按字节遍历字符串:\n")
|
||||
for i := 0; i < len(str2); i++ {
|
||||
fmt.Printf(" 字节 %d: %d ('%c')\n", i, str2[i], str2[i])
|
||||
if i >= 7 { // 限制输出
|
||||
fmt.Printf(" ...\n")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 统计字符类型
|
||||
fmt.Printf(" 统计字符类型:\n")
|
||||
text := "Hello, 世界! 123"
|
||||
ascii, unicode, digit, other := 0, 0, 0, 0
|
||||
|
||||
for _, char := range text {
|
||||
switch {
|
||||
case char >= 'A' && char <= 'Z' || char >= 'a' && char <= 'z':
|
||||
ascii++
|
||||
case char >= '0' && char <= '9':
|
||||
digit++
|
||||
case char > 127:
|
||||
unicode++
|
||||
default:
|
||||
other++
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf(" 文本: \"%s\"\n", text)
|
||||
fmt.Printf(" ASCII字母: %d, Unicode字符: %d, 数字: %d, 其他: %d\n",
|
||||
ascii, unicode, digit, other)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateRangeMap 演示 range 遍历映射
|
||||
func demonstrateRangeMap() {
|
||||
fmt.Println("3. range 遍历映射 (map):")
|
||||
|
||||
// 基本映射遍历
|
||||
fmt.Printf(" 遍历基本映射:\n")
|
||||
scores := map[string]int{
|
||||
"Alice": 95,
|
||||
"Bob": 87,
|
||||
"Charlie": 92,
|
||||
"David": 78,
|
||||
}
|
||||
|
||||
for name, score := range scores {
|
||||
fmt.Printf(" %s: %d分\n", name, score)
|
||||
}
|
||||
|
||||
// 注意:映射遍历顺序是随机的
|
||||
fmt.Printf(" 注意: 映射的遍历顺序是随机的\n")
|
||||
|
||||
// 遍历复杂映射
|
||||
fmt.Printf(" 遍历复杂映射:\n")
|
||||
students := map[string]map[string]interface{}{
|
||||
"student1": {
|
||||
"name": "张三",
|
||||
"age": 20,
|
||||
"grade": "A",
|
||||
},
|
||||
"student2": {
|
||||
"name": "李四",
|
||||
"age": 21,
|
||||
"grade": "B",
|
||||
},
|
||||
}
|
||||
|
||||
for id, info := range students {
|
||||
fmt.Printf(" 学生ID: %s\n", id)
|
||||
for key, value := range info {
|
||||
fmt.Printf(" %s: %v\n", key, value)
|
||||
}
|
||||
}
|
||||
|
||||
// 统计映射信息
|
||||
fmt.Printf(" 统计映射信息:\n")
|
||||
wordCount := map[string]int{
|
||||
"go": 10,
|
||||
"python": 8,
|
||||
"java": 15,
|
||||
"rust": 5,
|
||||
}
|
||||
|
||||
totalWords := 0
|
||||
maxCount := 0
|
||||
mostPopular := ""
|
||||
|
||||
for word, count := range wordCount {
|
||||
totalWords += count
|
||||
if count > maxCount {
|
||||
maxCount = count
|
||||
mostPopular = word
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf(" 词汇统计: %v\n", wordCount)
|
||||
fmt.Printf(" 总词数: %d\n", totalWords)
|
||||
fmt.Printf(" 最受欢迎的词: %s (%d次)\n", mostPopular, maxCount)
|
||||
|
||||
// 遍历空映射
|
||||
fmt.Printf(" 遍历空映射:\n")
|
||||
emptyMap := make(map[string]int)
|
||||
count := 0
|
||||
for range emptyMap {
|
||||
count++
|
||||
}
|
||||
fmt.Printf(" 空映射遍历次数: %d\n", count)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateRangeChannel 演示 range 遍历通道
|
||||
func demonstrateRangeChannel() {
|
||||
fmt.Println("4. range 遍历通道 (channel):")
|
||||
|
||||
fmt.Printf(" 基本通道遍历:\n")
|
||||
|
||||
// 创建一个通道并发送数据
|
||||
ch := make(chan int, 5)
|
||||
|
||||
// 发送数据到通道
|
||||
for i := 1; i <= 5; i++ {
|
||||
ch <- i * 10
|
||||
}
|
||||
close(ch) // 关闭通道,range 才能正常结束
|
||||
|
||||
// 使用 range 遍历通道
|
||||
for value := range ch {
|
||||
fmt.Printf(" 从通道接收: %d\n", value)
|
||||
}
|
||||
|
||||
// 字符串通道示例
|
||||
fmt.Printf(" 字符串通道遍历:\n")
|
||||
strCh := make(chan string, 3)
|
||||
|
||||
messages := []string{"Hello", "World", "Go"}
|
||||
for _, msg := range messages {
|
||||
strCh <- msg
|
||||
}
|
||||
close(strCh)
|
||||
|
||||
for message := range strCh {
|
||||
fmt.Printf(" 消息: %s\n", message)
|
||||
}
|
||||
|
||||
// 注意:如果通道没有关闭,range 会一直等待
|
||||
fmt.Printf(" 注意: 通道必须关闭,否则 range 会一直等待\n")
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateRangeValueCopy 演示 range 的值拷贝特性
|
||||
func demonstrateRangeValueCopy() {
|
||||
fmt.Println("5. range 的值拷贝特性:")
|
||||
|
||||
fmt.Printf(" range 会拷贝值,修改拷贝不会影响原始数据:\n")
|
||||
|
||||
// 结构体切片示例
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
people := []Person{
|
||||
{"Alice", 25},
|
||||
{"Bob", 30},
|
||||
{"Charlie", 35},
|
||||
}
|
||||
|
||||
fmt.Printf(" 原始数据:\n")
|
||||
for i, person := range people {
|
||||
fmt.Printf(" people[%d]: %+v\n", i, person)
|
||||
}
|
||||
|
||||
// 尝试修改 range 返回的值(不会影响原始数据)
|
||||
fmt.Printf(" 尝试修改 range 返回的值:\n")
|
||||
for i, person := range people {
|
||||
person.Age += 10 // 这不会修改原始数据
|
||||
fmt.Printf(" 修改后的拷贝 people[%d]: %+v\n", i, person)
|
||||
}
|
||||
|
||||
fmt.Printf(" 原始数据(未改变):\n")
|
||||
for i, person := range people {
|
||||
fmt.Printf(" people[%d]: %+v\n", i, person)
|
||||
}
|
||||
|
||||
// 正确的修改方式:使用索引
|
||||
fmt.Printf(" 正确的修改方式(使用索引):\n")
|
||||
for i := range people {
|
||||
people[i].Age += 5
|
||||
}
|
||||
|
||||
for i, person := range people {
|
||||
fmt.Printf(" people[%d]: %+v\n", i, person)
|
||||
}
|
||||
|
||||
// 指针切片的情况
|
||||
fmt.Printf(" 指针切片的情况:\n")
|
||||
ptrPeople := []*Person{
|
||||
{"David", 28},
|
||||
{"Eve", 32},
|
||||
}
|
||||
|
||||
// 通过指针修改(会影响原始数据)
|
||||
for _, personPtr := range ptrPeople {
|
||||
personPtr.Age += 2
|
||||
}
|
||||
|
||||
for i, personPtr := range ptrPeople {
|
||||
fmt.Printf(" ptrPeople[%d]: %+v\n", i, *personPtr)
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateIgnoreIndexValue 演示忽略索引或值
|
||||
func demonstrateIgnoreIndexValue() {
|
||||
fmt.Println("6. 忽略索引或值:")
|
||||
|
||||
// 只需要值,忽略索引
|
||||
fmt.Printf(" 只需要值,忽略索引(使用 _ ):\n")
|
||||
numbers := []int{1, 4, 9, 16, 25}
|
||||
sum := 0
|
||||
|
||||
for _, value := range numbers {
|
||||
sum += value
|
||||
}
|
||||
fmt.Printf(" 数组 %v 的和: %d\n", numbers, sum)
|
||||
|
||||
// 只需要索引,忽略值
|
||||
fmt.Printf(" 只需要索引,忽略值:\n")
|
||||
items := []string{"apple", "banana", "cherry", "date"}
|
||||
|
||||
for index := range items {
|
||||
fmt.Printf(" 索引 %d\n", index)
|
||||
}
|
||||
|
||||
// 既不需要索引也不需要值(只是计数)
|
||||
fmt.Printf(" 只计算元素个数:\n")
|
||||
data := []float64{1.1, 2.2, 3.3, 4.4, 5.5}
|
||||
count := 0
|
||||
|
||||
for range data {
|
||||
count++
|
||||
}
|
||||
fmt.Printf(" 元素个数: %d\n", count)
|
||||
|
||||
// 映射中忽略键或值
|
||||
fmt.Printf(" 映射中忽略键或值:\n")
|
||||
grades := map[string]int{
|
||||
"Math": 90,
|
||||
"English": 85,
|
||||
"Science": 92,
|
||||
}
|
||||
|
||||
// 只要值
|
||||
fmt.Printf(" 所有分数: ")
|
||||
for _, score := range grades {
|
||||
fmt.Printf("%d ", score)
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
|
||||
// 只要键
|
||||
fmt.Printf(" 所有科目: ")
|
||||
for subject := range grades {
|
||||
fmt.Printf("%s ", subject)
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstratePracticalExamples 演示 range 的实际应用
|
||||
func demonstratePracticalExamples() {
|
||||
fmt.Println("7. range 的实际应用:")
|
||||
|
||||
// 示例1: 数据统计
|
||||
fmt.Printf(" 示例1 - 销售数据统计:\n")
|
||||
sales := map[string][]int{
|
||||
"Q1": {100, 120, 110, 130},
|
||||
"Q2": {140, 135, 150, 145},
|
||||
"Q3": {160, 155, 170, 165},
|
||||
"Q4": {180, 175, 190, 185},
|
||||
}
|
||||
|
||||
yearTotal := 0
|
||||
for quarter, monthlySales := range sales {
|
||||
quarterTotal := 0
|
||||
for _, monthSale := range monthlySales {
|
||||
quarterTotal += monthSale
|
||||
}
|
||||
yearTotal += quarterTotal
|
||||
fmt.Printf(" %s 季度总销售额: %d\n", quarter, quarterTotal)
|
||||
}
|
||||
fmt.Printf(" 全年总销售额: %d\n", yearTotal)
|
||||
|
||||
// 示例2: 配置文件处理
|
||||
fmt.Printf(" 示例2 - 配置文件处理:\n")
|
||||
config := map[string]interface{}{
|
||||
"server_port": 8080,
|
||||
"debug_mode": true,
|
||||
"database_url": "localhost:5432",
|
||||
"max_connections": 100,
|
||||
"timeout": 30.5,
|
||||
}
|
||||
|
||||
for key, value := range config {
|
||||
fmt.Printf(" 配置项 %s: ", key)
|
||||
switch v := value.(type) {
|
||||
case int:
|
||||
fmt.Printf("%d (整数)\n", v)
|
||||
case bool:
|
||||
fmt.Printf("%t (布尔值)\n", v)
|
||||
case string:
|
||||
fmt.Printf("\"%s\" (字符串)\n", v)
|
||||
case float64:
|
||||
fmt.Printf("%.1f (浮点数)\n", v)
|
||||
default:
|
||||
fmt.Printf("%v (未知类型)\n", v)
|
||||
}
|
||||
}
|
||||
|
||||
// 示例3: 文本处理
|
||||
fmt.Printf(" 示例3 - 单词频率统计:\n")
|
||||
text := "go is great go is simple go is fast"
|
||||
words := []string{"go", "is", "great", "go", "is", "simple", "go", "is", "fast"}
|
||||
|
||||
wordFreq := make(map[string]int)
|
||||
for _, word := range words {
|
||||
wordFreq[word]++
|
||||
}
|
||||
|
||||
fmt.Printf(" 文本: \"%s\"\n", text)
|
||||
fmt.Printf(" 词频统计:\n")
|
||||
for word, freq := range wordFreq {
|
||||
fmt.Printf(" \"%s\": %d次\n", word, freq)
|
||||
}
|
||||
|
||||
// 示例4: 数据验证
|
||||
fmt.Printf(" 示例4 - 用户数据验证:\n")
|
||||
users := []map[string]string{
|
||||
{"name": "Alice", "email": "alice@example.com", "age": "25"},
|
||||
{"name": "", "email": "bob@test.com", "age": "30"},
|
||||
{"name": "Charlie", "email": "invalid-email", "age": "abc"},
|
||||
{"name": "David", "email": "david@domain.org", "age": "28"},
|
||||
}
|
||||
|
||||
validUsers := 0
|
||||
for i, user := range users {
|
||||
fmt.Printf(" 用户 %d: ", i+1)
|
||||
isValid := true
|
||||
|
||||
// 验证姓名
|
||||
if user["name"] == "" {
|
||||
fmt.Printf("姓名为空 ")
|
||||
isValid = false
|
||||
}
|
||||
|
||||
// 验证邮箱(简单验证)
|
||||
email := user["email"]
|
||||
if !contains(email, "@") || !contains(email, ".") {
|
||||
fmt.Printf("邮箱无效 ")
|
||||
isValid = false
|
||||
}
|
||||
|
||||
// 验证年龄
|
||||
age := user["age"]
|
||||
if !isNumeric(age) {
|
||||
fmt.Printf("年龄无效 ")
|
||||
isValid = false
|
||||
}
|
||||
|
||||
if isValid {
|
||||
fmt.Printf("✓ 有效用户\n")
|
||||
validUsers++
|
||||
} else {
|
||||
fmt.Printf("✗ 无效用户\n")
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf(" 有效用户数: %d/%d\n", validUsers, len(users))
|
||||
|
||||
// 示例5: 矩阵操作
|
||||
fmt.Printf(" 示例5 - 矩阵转置:\n")
|
||||
matrix := [][]int{
|
||||
{1, 2, 3},
|
||||
{4, 5, 6},
|
||||
}
|
||||
|
||||
fmt.Printf(" 原矩阵:\n")
|
||||
for i, row := range matrix {
|
||||
fmt.Printf(" 行 %d: %v\n", i, row)
|
||||
}
|
||||
|
||||
// 创建转置矩阵
|
||||
if len(matrix) > 0 {
|
||||
transposed := make([][]int, len(matrix[0]))
|
||||
for i := range transposed {
|
||||
transposed[i] = make([]int, len(matrix))
|
||||
}
|
||||
|
||||
for i, row := range matrix {
|
||||
for j, value := range row {
|
||||
transposed[j][i] = value
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf(" 转置矩阵:\n")
|
||||
for i, row := range transposed {
|
||||
fmt.Printf(" 行 %d: %v\n", i, row)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstratePerformanceConsiderations 演示 range 的性能考虑
|
||||
func demonstratePerformanceConsiderations() {
|
||||
fmt.Println("8. range 的性能考虑:")
|
||||
|
||||
// 大切片的遍历
|
||||
fmt.Printf(" 大切片的遍历性能:\n")
|
||||
largeSlice := make([]int, 1000)
|
||||
for i := range largeSlice {
|
||||
largeSlice[i] = i
|
||||
}
|
||||
|
||||
// 使用 range(推荐)
|
||||
sum1 := 0
|
||||
for _, value := range largeSlice {
|
||||
sum1 += value
|
||||
if sum1 > 100 { // 提前退出演示
|
||||
break
|
||||
}
|
||||
}
|
||||
fmt.Printf(" 使用 range 遍历(推荐): 部分和 = %d\n", sum1)
|
||||
|
||||
// 使用传统 for 循环
|
||||
sum2 := 0
|
||||
for i := 0; i < len(largeSlice); i++ {
|
||||
sum2 += largeSlice[i]
|
||||
if sum2 > 100 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fmt.Printf(" 使用传统 for 循环: 部分和 = %d\n", sum2)
|
||||
|
||||
// 字符串遍历的性能
|
||||
fmt.Printf(" 字符串遍历的性能考虑:\n")
|
||||
longString := "这是一个包含中文字符的长字符串,用于演示遍历性能"
|
||||
|
||||
// 使用 range(处理 Unicode 正确)
|
||||
charCount1 := 0
|
||||
for range longString {
|
||||
charCount1++
|
||||
}
|
||||
fmt.Printf(" 使用 range 统计字符数: %d\n", charCount1)
|
||||
|
||||
// 使用 len(字节数,不是字符数)
|
||||
byteCount := len(longString)
|
||||
fmt.Printf(" 使用 len 统计字节数: %d\n", byteCount)
|
||||
|
||||
// 使用 utf8.RuneCountInString(正确的字符数)
|
||||
charCount2 := utf8.RuneCountInString(longString)
|
||||
fmt.Printf(" 使用 utf8.RuneCountInString 统计字符数: %d\n", charCount2)
|
||||
|
||||
// 映射遍历的注意事项
|
||||
fmt.Printf(" 映射遍历的注意事项:\n")
|
||||
largeMap := make(map[int]string)
|
||||
for i := 0; i < 10; i++ {
|
||||
largeMap[i] = fmt.Sprintf("value_%d", i)
|
||||
}
|
||||
|
||||
fmt.Printf(" 映射大小: %d\n", len(largeMap))
|
||||
fmt.Printf(" 映射遍历顺序是随机的,每次运行可能不同\n")
|
||||
|
||||
// 显示前几个元素
|
||||
count := 0
|
||||
for key, value := range largeMap {
|
||||
fmt.Printf(" %d: %s\n", key, value)
|
||||
count++
|
||||
if count >= 3 {
|
||||
fmt.Printf(" ...\n")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// 辅助函数
|
||||
func contains(s, substr string) bool {
|
||||
for i := 0; i <= len(s)-len(substr); i++ {
|
||||
if s[i:i+len(substr)] == substr {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isNumeric(s string) bool {
|
||||
if len(s) == 0 {
|
||||
return false
|
||||
}
|
||||
for _, char := range s {
|
||||
if char < '0' || char > '9' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/*
|
||||
运行这个程序:
|
||||
go run 04-range.go
|
||||
|
||||
学习要点:
|
||||
1. range 是 Go 中遍历集合类型的标准方式
|
||||
2. range 可以用于数组、切片、字符串、映射和通道
|
||||
3. range 返回索引/键和值,可以用 _ 忽略不需要的部分
|
||||
4. range 会拷贝值,修改拷贝不会影响原始数据
|
||||
5. 字符串的 range 遍历按 Unicode 字符,索引是字节位置
|
||||
|
||||
range 的语法:
|
||||
- for index, value := range collection { ... }
|
||||
- for index := range collection { ... } // 只要索引/键
|
||||
- for _, value := range collection { ... } // 只要值
|
||||
- for range collection { ... } // 只计数
|
||||
|
||||
不同类型的 range:
|
||||
1. 数组/切片: 返回索引和值
|
||||
2. 字符串: 返回字节位置和 Unicode 字符
|
||||
3. 映射: 返回键和值(顺序随机)
|
||||
4. 通道: 返回接收到的值(通道需要关闭)
|
||||
|
||||
性能考虑:
|
||||
1. range 通常比传统 for 循环更高效和安全
|
||||
2. 字符串的 range 正确处理 Unicode 字符
|
||||
3. 大集合的遍历考虑提前退出
|
||||
4. 映射遍历顺序是随机的
|
||||
|
||||
最佳实践:
|
||||
1. 优先使用 range 遍历集合
|
||||
2. 使用 _ 忽略不需要的返回值
|
||||
3. 注意 range 的值拷贝特性
|
||||
4. 字符串处理时考虑 Unicode 字符
|
||||
5. 通道遍历前确保通道会被关闭
|
||||
|
||||
常见应用场景:
|
||||
1. 数据处理和统计
|
||||
2. 配置文件解析
|
||||
3. 文本分析
|
||||
4. 数据验证
|
||||
5. 矩阵操作
|
||||
6. 集合操作
|
||||
*/
|
15
golang-learning/02-control-flow/README.md
Normal file
15
golang-learning/02-control-flow/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# 第二章:控制流程
|
||||
|
||||
本章将学习 Go 语言的控制流程语句,包括条件判断、分支选择和循环结构。
|
||||
|
||||
## 学习目标
|
||||
- 掌握条件语句的使用
|
||||
- 理解 switch 语句的特点
|
||||
- 学会使用各种形式的 for 循环
|
||||
- 了解 range 关键字的用法
|
||||
|
||||
## 文件列表
|
||||
- `01-if-else.go` - 条件判断语句
|
||||
- `02-switch.go` - 分支选择语句
|
||||
- `03-for-loops.go` - 循环语句
|
||||
- `04-range.go` - 范围遍历
|
Reference in New Issue
Block a user