commit e51feb129668f74cf638a1630c546fcff3765803 Author: estel <690930@qq.com> Date: Sun Aug 24 01:01:26 2025 +0800 初始提交 diff --git a/.kiro/specs/golang-learning-guide/design.md b/.kiro/specs/golang-learning-guide/design.md new file mode 100644 index 0000000..7154511 --- /dev/null +++ b/.kiro/specs/golang-learning-guide/design.md @@ -0,0 +1,231 @@ +# Go 语言学习指南设计文档 + +## 概述 + +本项目将创建一个结构化的 Go 语言学习资源,通过一系列精心设计的 .go 文件,每个文件专注于特定的 Go 语言概念。项目采用渐进式学习方法,从基础语法开始,逐步深入到高级特性。 + +## 架构 + +### 项目结构 +``` +golang-learning/ +├── README.md # 学习指南和目录 +├── go.mod # Go 模块文件 +├── 01-basics/ # 基础语法 +│ ├── 01-hello-world.go +│ ├── 02-variables.go +│ ├── 03-constants.go +│ ├── 04-data-types.go +│ └── 05-operators.go +├── 02-control-flow/ # 控制流程 +│ ├── 01-if-else.go +│ ├── 02-switch.go +│ ├── 03-for-loops.go +│ └── 04-range.go +├── 03-functions/ # 函数和方法 +│ ├── 01-basic-functions.go +│ ├── 02-multiple-returns.go +│ ├── 03-variadic-functions.go +│ ├── 04-closures.go +│ └── 05-methods.go +├── 04-data-structures/ # 数据结构 +│ ├── 01-arrays.go +│ ├── 02-slices.go +│ ├── 03-maps.go +│ ├── 04-structs.go +│ └── 05-pointers.go +├── 05-interfaces/ # 接口 +│ ├── 01-basic-interfaces.go +│ ├── 02-empty-interface.go +│ └── 03-type-assertions.go +├── 06-concurrency/ # 并发编程 +│ ├── 01-goroutines.go +│ ├── 02-channels.go +│ ├── 03-select.go +│ ├── 04-sync-package.go +│ └── 05-worker-pools.go +├── 07-error-handling/ # 错误处理 +│ ├── 01-basic-errors.go +│ ├── 02-custom-errors.go +│ └── 03-panic-recover.go +├── 08-packages/ # 包管理 +│ ├── 01-creating-packages.go +│ ├── 02-importing-packages.go +│ └── utils/ +│ └── helper.go +├── 09-advanced/ # 高级特性 +│ ├── 01-reflection.go +│ ├── 02-generics.go +│ ├── 03-context.go +│ └── 04-testing.go +└── 10-projects/ # 实践项目 + ├── 01-calculator/ + ├── 02-todo-list/ + └── 03-web-server/ +``` + +## 组件和接口 + +### 学习模块设计 + +每个 .go 文件将遵循统一的结构: + +1. **文件头注释**:说明学习目标和知识点 +2. **包声明**:适当的包名 +3. **导入语句**:所需的标准库 +4. **示例函数**:多个演示不同概念的函数 +5. **主函数**:运行所有示例的入口点 +6. **详细注释**:中文解释每行代码的作用 + +### 代码注释规范 + +- 使用中文注释,便于初学者理解 +- 每个重要概念都有详细说明 +- 包含常见错误和注意事项 +- 提供相关概念的扩展阅读建议 + +### 示例代码规范 + +- 每个概念至少提供 2-3 个不同的示例 +- 从简单到复杂的渐进式展示 +- 包含实际应用场景的代码 +- 提供可运行的完整示例 + +## 数据模型 + +### 学习进度跟踪 + +虽然这是静态文件学习,但设计中考虑了学习进度的概念: + +```go +type LearningModule struct { + Name string + Description string + Files []string + Prerequisites []string + Difficulty int // 1-5 难度等级 +} + +type LearningPath struct { + Modules []LearningModule + CurrentModule int +} +``` + +### 代码示例结构 + +```go +type CodeExample struct { + Title string + Description string + Code string + Output string + Notes []string +} +``` + +## 错误处理 + +### 学习过程中的常见问题 + +1. **编译错误处理** + - 每个文件都应该能够独立编译和运行 + - 提供常见编译错误的解决方案 + - 在注释中说明可能遇到的问题 + +2. **运行时错误处理** + - 演示正确的错误处理模式 + - 展示如何避免常见的运行时错误 + - 提供调试技巧和方法 + +3. **学习困难处理** + - 在复杂概念前提供充分的背景知识 + - 提供多种理解角度和类比 + - 包含练习建议和扩展阅读 + +## 测试策略 + +### 代码验证 + +1. **语法正确性** + - 所有代码文件都应该能够成功编译 + - 使用 `go fmt` 确保代码格式一致 + - 使用 `go vet` 检查潜在问题 + +2. **示例有效性** + - 每个示例都应该产生预期的输出 + - 包含边界情况的测试 + - 验证错误处理的正确性 + +3. **学习效果验证** + - 在每个模块末尾提供小测验 + - 包含实践练习题 + - 提供解答和解释 + +### 文档质量保证 + +1. **注释完整性** + - 确保每个重要概念都有解释 + - 检查中文表达的准确性 + - 验证技术术语的正确使用 + +2. **示例多样性** + - 确保涵盖不同的使用场景 + - 包含实际项目中的应用示例 + - 提供最佳实践的演示 + +## 学习路径设计 + +### 推荐学习顺序 + +1. **第一阶段:基础入门(1-2周)** + - 01-basics: 基础语法和数据类型 + - 02-control-flow: 控制流程结构 + +2. **第二阶段:函数和数据(2-3周)** + - 03-functions: 函数定义和使用 + - 04-data-structures: 数据结构操作 + +3. **第三阶段:面向对象(1-2周)** + - 05-interfaces: 接口和多态 + +4. **第四阶段:并发编程(2-3周)** + - 06-concurrency: Go 的并发特性 + +5. **第五阶段:工程实践(2-3周)** + - 07-error-handling: 错误处理 + - 08-packages: 包管理 + +6. **第六阶段:高级特性(2-3周)** + - 09-advanced: 反射、泛型等高级特性 + +7. **第七阶段:实践项目(3-4周)** + - 10-projects: 完整项目开发 + +### 学习建议 + +- 每天学习 1-2 个文件 +- 必须动手运行每个示例 +- 尝试修改代码观察结果变化 +- 完成每个模块的练习题 +- 定期回顾之前学过的内容 + +## 扩展性设计 + +### 内容更新机制 + +- 模块化设计便于添加新内容 +- 版本控制跟踪学习资源的更新 +- 社区贡献的示例和练习 + +### 个性化学习 + +- 不同难度级别的示例 +- 针对不同背景学习者的说明 +- 可选的深入学习材料 + +### 工具集成 + +- 与 IDE 的集成建议 +- 调试工具的使用说明 +- 性能分析工具的介绍 \ No newline at end of file diff --git a/.kiro/specs/golang-learning-guide/requirements.md b/.kiro/specs/golang-learning-guide/requirements.md new file mode 100644 index 0000000..23fa10b --- /dev/null +++ b/.kiro/specs/golang-learning-guide/requirements.md @@ -0,0 +1,87 @@ +# Go 语言学习指南需求文档 + +## 介绍 + +这个项目旨在为 Go 语言初学者创建一个全面、系统化的学习资源。通过创建一系列结构化的 .go 文件,每个文件专注于特定的 Go 语言概念和语法,帮助初学者循序渐进地掌握 Go 编程。 + +## 需求 + +### 需求 1:基础语法学习模块 + +**用户故事:** 作为一个 Go 语言初学者,我想要学习 Go 的基础语法,以便能够编写简单的 Go 程序。 + +#### 验收标准 + +1. 当学习者查看基础语法文件时,系统应该提供变量声明、数据类型、常量定义的完整示例 +2. 当学习者运行基础语法示例时,系统应该展示每种语法的输出结果 +3. 当学习者需要理解语法时,系统应该提供详细的中文注释说明 + +### 需求 2:控制流程学习模块 + +**用户故事:** 作为一个 Go 语言初学者,我想要学习条件语句和循环结构,以便能够编写逻辑控制程序。 + +#### 验收标准 + +1. 当学习者查看控制流程文件时,系统应该提供 if/else、switch、for 循环的完整示例 +2. 当学习者运行控制流程示例时,系统应该展示不同条件下的执行路径 +3. 当学习者需要练习时,系统应该提供多个实际应用场景的示例 + +### 需求 3:函数和方法学习模块 + +**用户故事:** 作为一个 Go 语言初学者,我想要学习函数定义和方法调用,以便能够编写模块化的代码。 + +#### 验收标准 + +1. 当学习者查看函数文件时,系统应该提供函数定义、参数传递、返回值的示例 +2. 当学习者学习方法时,系统应该展示结构体方法和接口方法的区别 +3. 当学习者需要理解作用域时,系统应该提供变量作用域的详细说明 + +### 需求 4:数据结构学习模块 + +**用户故事:** 作为一个 Go 语言初学者,我想要学习 Go 的内置数据结构,以便能够处理复杂的数据。 + +#### 验收标准 + +1. 当学习者查看数据结构文件时,系统应该提供数组、切片、映射、结构体的完整示例 +2. 当学习者操作数据结构时,系统应该展示增删改查的各种操作方法 +3. 当学习者需要选择数据结构时,系统应该提供使用场景的建议 + +### 需求 5:并发编程学习模块 + +**用户故事:** 作为一个 Go 语言初学者,我想要学习 Go 的并发特性,以便能够编写高效的并发程序。 + +#### 验收标准 + +1. 当学习者查看并发文件时,系统应该提供 goroutine 和 channel 的基础示例 +2. 当学习者学习同步时,系统应该展示 sync 包的使用方法 +3. 当学习者需要避免竞态条件时,系统应该提供最佳实践示例 + +### 需求 6:错误处理学习模块 + +**用户故事:** 作为一个 Go 语言初学者,我想要学习 Go 的错误处理机制,以便能够编写健壮的程序。 + +#### 验收标准 + +1. 当学习者查看错误处理文件时,系统应该提供 error 接口的使用示例 +2. 当学习者处理错误时,系统应该展示自定义错误类型的创建方法 +3. 当学习者需要调试时,系统应该提供错误处理的最佳实践 + +### 需求 7:包管理学习模块 + +**用户故事:** 作为一个 Go 语言初学者,我想要学习 Go 的包管理系统,以便能够组织和重用代码。 + +#### 验收标准 + +1. 当学习者查看包管理文件时,系统应该提供包的创建和导入示例 +2. 当学习者使用第三方包时,系统应该展示 go mod 的使用方法 +3. 当学习者需要发布包时,系统应该提供包结构的最佳实践 + +### 需求 8:学习路径指导 + +**用户故事:** 作为一个 Go 语言初学者,我想要有一个清晰的学习顺序,以便能够循序渐进地掌握 Go 语言。 + +#### 验收标准 + +1. 当学习者开始学习时,系统应该提供推荐的学习顺序 +2. 当学习者完成一个模块时,系统应该指导下一步学习内容 +3. 当学习者需要复习时,系统应该提供知识点之间的关联说明 \ No newline at end of file diff --git a/.kiro/specs/golang-learning-guide/tasks.md b/.kiro/specs/golang-learning-guide/tasks.md new file mode 100644 index 0000000..a3c6e40 --- /dev/null +++ b/.kiro/specs/golang-learning-guide/tasks.md @@ -0,0 +1,133 @@ +# Go 语言学习指南实现计划 + +- [x] 1. 创建项目基础结构和配置文件 + - 创建根目录结构和 go.mod 文件 + - 编写项目主 README.md 文件,包含完整的学习指南和目录 + - 创建所有子目录的结构 + - _需求: 8.1, 8.2_ + +- [ ] 2. 实现基础语法学习模块 +- [x] 2.1 创建 Hello World 和变量示例 + - 编写 01-basics/01-hello-world.go,展示基本程序结构 + - 编写 01-basics/02-variables.go,演示变量声明和初始化的各种方式 + - 包含详细的中文注释说明每种语法的用法 + - _需求: 1.1, 1.2, 1.3_ + +- [x] 2.2 创建常量和数据类型示例 + - 编写 01-basics/03-constants.go,展示常量定义和使用 + - 编写 01-basics/04-data-types.go,演示所有基本数据类型 + - 编写 01-basics/05-operators.go,展示各种运算符的使用 + - _需求: 1.1, 1.2, 1.3_ + +- [ ] 3. 实现控制流程学习模块 +- [x] 3.1 创建条件语句示例 + - 编写 02-control-flow/01-if-else.go,展示条件判断的各种形式 + - 编写 02-control-flow/02-switch.go,演示 switch 语句的不同用法 + - 包含多个实际应用场景的示例 + - _需求: 2.1, 2.2, 2.3_ + +- [x] 3.2 创建循环结构示例 + - 编写 02-control-flow/03-for-loops.go,展示 for 循环的各种形式 + - 编写 02-control-flow/04-range.go,演示 range 关键字的使用 + - 提供不同条件下的执行路径示例 + - _需求: 2.1, 2.2, 2.3_ + +- [ ] 4. 实现函数和方法学习模块 +- [x] 4.1 创建基础函数示例 + - 编写 03-functions/01-basic-functions.go,展示函数定义和调用 + - 编写 03-functions/02-multiple-returns.go,演示多返回值函数 + - 编写 03-functions/03-variadic-functions.go,展示可变参数函数 + - _需求: 3.1, 3.2, 3.3_ + +- [x] 4.2 创建高级函数特性示例 + - 编写 03-functions/04-closures.go,演示闭包的概念和使用 + - 编写 03-functions/05-methods.go,展示结构体方法的定义和使用 + - 提供变量作用域的详细说明和示例 + - _需求: 3.1, 3.2, 3.3_ + +- [ ] 5. 实现数据结构学习模块 +- [-] 5.1 创建基本数据结构示例 + - 编写 04-data-structures/01-arrays.go,展示数组的创建和操作 + - 编写 04-data-structures/02-slices.go,演示切片的各种操作方法 + - 编写 04-data-structures/03-maps.go,展示映射的增删改查操作 + - _需求: 4.1, 4.2, 4.3_ + +- [ ] 5.2 创建复合数据结构示例 + - 编写 04-data-structures/04-structs.go,展示结构体的定义和使用 + - 编写 04-data-structures/05-pointers.go,演示指针的概念和操作 + - 提供不同数据结构的使用场景建议 + - _需求: 4.1, 4.2, 4.3_ + +- [ ] 6. 实现接口学习模块 +- [ ] 6.1 创建接口基础示例 + - 编写 05-interfaces/01-basic-interfaces.go,展示接口的定义和实现 + - 编写 05-interfaces/02-empty-interface.go,演示空接口的使用 + - 编写 05-interfaces/03-type-assertions.go,展示类型断言的使用 + - _需求: 3.2_ + +- [ ] 7. 实现并发编程学习模块 +- [ ] 7.1 创建 Goroutine 和 Channel 示例 + - 编写 06-concurrency/01-goroutines.go,展示 goroutine 的基础使用 + - 编写 06-concurrency/02-channels.go,演示 channel 的各种操作 + - 编写 06-concurrency/03-select.go,展示 select 语句的使用 + - _需求: 5.1, 5.2, 5.3_ + +- [ ] 7.2 创建同步和高级并发示例 + - 编写 06-concurrency/04-sync-package.go,展示 sync 包的使用方法 + - 编写 06-concurrency/05-worker-pools.go,演示工作池模式 + - 提供避免竞态条件的最佳实践示例 + - _需求: 5.1, 5.2, 5.3_ + +- [ ] 8. 实现错误处理学习模块 +- [ ] 8.1 创建错误处理示例 + - 编写 07-error-handling/01-basic-errors.go,展示基本错误处理 + - 编写 07-error-handling/02-custom-errors.go,演示自定义错误类型 + - 编写 07-error-handling/03-panic-recover.go,展示 panic 和 recover 的使用 + - _需求: 6.1, 6.2, 6.3_ + +- [ ] 9. 实现包管理学习模块 +- [ ] 9.1 创建包管理示例 + - 编写 08-packages/01-creating-packages.go,展示包的创建方法 + - 编写 08-packages/02-importing-packages.go,演示包的导入和使用 + - 创建 08-packages/utils/helper.go,提供实际的包示例 + - _需求: 7.1, 7.2, 7.3_ + +- [ ] 10. 实现高级特性学习模块 +- [ ] 10.1 创建高级特性示例 + - 编写 09-advanced/01-reflection.go,展示反射的基本使用 + - 编写 09-advanced/02-generics.go,演示泛型的语法和应用 + - 编写 09-advanced/03-context.go,展示 context 包的使用 + - 编写 09-advanced/04-testing.go,演示单元测试的编写方法 + - _需求: 各个高级特性需求_ + +- [ ] 11. 创建实践项目模块 +- [ ] 11.1 实现计算器项目 + - 创建 10-projects/01-calculator/ 目录结构 + - 编写简单计算器的完整实现,包含基本四则运算 + - 提供项目结构说明和运行指导 + - _需求: 综合应用各种语法特性_ + +- [ ] 11.2 实现待办事项列表项目 + - 创建 10-projects/02-todo-list/ 目录结构 + - 编写命令行待办事项管理程序 + - 包含数据持久化和用户交互功能 + - _需求: 综合应用数据结构和文件操作_ + +- [ ] 11.3 实现简单 Web 服务器项目 + - 创建 10-projects/03-web-server/ 目录结构 + - 编写基础的 HTTP 服务器实现 + - 包含路由处理和 JSON API 示例 + - _需求: 综合应用并发和网络编程_ + +- [ ] 12. 完善文档和测试 +- [ ] 12.1 添加学习指导文档 + - 在每个目录下创建 README.md 文件,说明该模块的学习重点 + - 添加常见问题解答和学习建议 + - 提供练习题和扩展阅读材料 + - _需求: 8.1, 8.2, 8.3_ + +- [ ] 12.2 验证所有代码示例 + - 确保所有 .go 文件都能成功编译和运行 + - 验证输出结果的正确性 + - 检查注释的完整性和准确性 + - _需求: 所有模块的验收标准_ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..5480842 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "kiroAgent.configureMCP": "Disabled" +} \ No newline at end of file diff --git a/golang-learning/01-basics/01-hello-world.go b/golang-learning/01-basics/01-hello-world.go new file mode 100644 index 0000000..b1e9121 --- /dev/null +++ b/golang-learning/01-basics/01-hello-world.go @@ -0,0 +1,119 @@ +/* +01-hello-world.go - Go 语言入门第一课 + +学习目标: +1. 了解 Go 程序的基本结构 +2. 理解包(package)的概念 +3. 学会使用 fmt 包进行输出 +4. 掌握 main 函数的作用 + +知识点: +- package 声明 +- import 导入 +- main 函数 +- fmt.Println 输出函数 +*/ + +// 每个 Go 文件都必须以 package 声明开始 +// main 包是特殊的包,表示这是一个可执行程序 +package main + +// import 用于导入其他包 +// fmt 包提供了格式化输入输出的功能 +import "fmt" + +// main 函数是程序的入口点 +// 当运行程序时,会自动执行 main 函数 +func main() { + // fmt.Println 用于输出文本并自动换行 + fmt.Println("Hello, World!") + fmt.Println("欢迎来到 Go 语言的世界!") + + // 你也可以使用 fmt.Print(不换行)或 fmt.Printf(格式化输出) + fmt.Print("这是 ") + fmt.Print("同一行的输出\n") // \n 表示换行 + + // fmt.Printf 支持格式化输出,类似于 C 语言的 printf + name := "Go" + version := 1.21 + fmt.Printf("我正在学习 %s 语言,版本是 %.2f\n", name, version) + + // 多种输出方式的演示 + demonstrateOutput() +} + +// demonstrateOutput 演示不同的输出方式 +func demonstrateOutput() { + fmt.Println("\n=== 输出方式演示 ===") + + // 1. 基本输出 + fmt.Println("1. fmt.Println - 输出并换行") + + // 2. 不换行输出 + fmt.Print("2. fmt.Print - ") + fmt.Print("不换行输出") + fmt.Print("\n") // 手动换行 + + // 3. 格式化输出 + age := 25 + height := 175.5 + isStudent := true + + fmt.Printf("3. fmt.Printf - 格式化输出:\n") + fmt.Printf(" 年龄: %d 岁\n", age) // %d 表示整数 + fmt.Printf(" 身高: %.1f cm\n", height) // %.1f 表示保留1位小数的浮点数 + fmt.Printf(" 是学生: %t\n", isStudent) // %t 表示布尔值 + fmt.Printf(" 十六进制年龄: %x\n", age) // %x 表示十六进制 + fmt.Printf(" 八进制年龄: %o\n", age) // %o 表示八进制 + + // 4. 通用格式符 %v + fmt.Printf("4. 通用格式符 %%v:\n") + fmt.Printf(" 年龄: %v, 身高: %v, 是学生: %v\n", age, height, isStudent) + + // 5. 详细格式符 %+v 和 %#v(主要用于结构体) + person := struct { + Name string + Age int + }{"张三", 30} + + fmt.Printf("5. 结构体输出:\n") + fmt.Printf(" %%v: %v\n", person) // 简单格式 + fmt.Printf(" %%+v: %+v\n", person) // 包含字段名 + fmt.Printf(" %%#v: %#v\n", person) // Go 语法格式 +} + +/* +运行这个程序: +1. 在终端中进入 01-basics 目录 +2. 执行命令:go run 01-hello-world.go + +预期输出: +Hello, World! +欢迎来到 Go 语言的世界! +这是 同一行的输出 +我正在学习 Go 语言,版本是 1.21 + +=== 输出方式演示 === +1. fmt.Println - 输出并换行 +2. fmt.Print - 不换行输出 +3. fmt.Printf - 格式化输出: + 年龄: 25 岁 + 身高: 175.5 cm + 是学生: true + 十六进制年龄: 19 + 八进制年龄: 31 +4. 通用格式符 %v: + 年龄: 25, 身高: 175.5, 是学生: true +5. 结构体输出: + %v: {张三 30} + %+v: {Name:张三 Age:30} + %#v: struct { Name string; Age int }{Name:"张三", Age:30} + +学习要点: +1. Go 程序必须有 package 声明 +2. main 包表示可执行程序 +3. main 函数是程序入口 +4. 使用 import 导入需要的包 +5. fmt 包提供了丰富的输出功能 +6. 注释使用 // 或 +*/ \ No newline at end of file diff --git a/golang-learning/01-basics/02-variables.go b/golang-learning/01-basics/02-variables.go new file mode 100644 index 0000000..4b468bd --- /dev/null +++ b/golang-learning/01-basics/02-variables.go @@ -0,0 +1,258 @@ +/* +02-variables.go - Go 语言变量详解 + +学习目标: +1. 掌握变量声明的多种方式 +2. 理解 Go 的类型推断 +3. 学会使用短变量声明 +4. 了解变量的作用域 +5. 掌握零值的概念 + +知识点: +- var 关键字声明 +- 短变量声明 := +- 类型推断 +- 零值 +- 变量作用域 +- 多变量声明 +*/ + +package main + +import "fmt" + +// 包级别变量声明(全局变量) +var globalVar = "我是全局变量" +var ( + // 使用括号可以声明多个变量 + packageVar1 = "包变量1" + packageVar2 = "包变量2" + packageVar3 int = 100 +) + +func main() { + fmt.Println("=== Go 语言变量详解 ===\n") + + // 演示各种变量声明方式 + demonstrateVariableDeclaration() + + // 演示零值 + demonstrateZeroValues() + + // 演示类型推断 + demonstrateTypeInference() + + // 演示多变量声明 + demonstrateMultipleDeclaration() + + // 演示变量作用域 + demonstrateScope() + + // 演示变量赋值和修改 + demonstrateAssignment() +} + +// demonstrateVariableDeclaration 演示变量声明的不同方式 +func demonstrateVariableDeclaration() { + fmt.Println("1. 变量声明方式:") + + // 方式1: var 关键字 + 类型声明 + var name string + name = "张三" + fmt.Printf(" 方式1 - var name string: %s\n", name) + + // 方式2: var 关键字 + 类型声明 + 初始化 + var age int = 25 + fmt.Printf(" 方式2 - var age int = 25: %d\n", age) + + // 方式3: var 关键字 + 类型推断 + var city = "北京" // Go 会自动推断为 string 类型 + fmt.Printf(" 方式3 - var city = \"北京\": %s\n", city) + + // 方式4: 短变量声明(最常用) + height := 175.5 // 自动推断为 float64 类型 + fmt.Printf(" 方式4 - height := 175.5: %.1f\n", height) + + // 注意:短变量声明只能在函数内部使用 + // 在包级别必须使用 var 关键字 + + fmt.Println() +} + +// demonstrateZeroValues 演示 Go 的零值概念 +func demonstrateZeroValues() { + fmt.Println("2. 零值演示:") + fmt.Println(" Go 中每种类型都有默认的零值") + + // 声明变量但不初始化,会自动赋予零值 + var intVar int + var floatVar float64 + var boolVar bool + var stringVar string + var pointerVar *int + + fmt.Printf(" int 零值: %d\n", intVar) // 0 + fmt.Printf(" float64 零值: %f\n", floatVar) // 0.000000 + fmt.Printf(" bool 零值: %t\n", boolVar) // false + fmt.Printf(" string 零值: '%s'\n", stringVar) // ""(空字符串) + fmt.Printf(" pointer 零值: %v\n", pointerVar) // + + fmt.Println() +} + +// demonstrateTypeInference 演示类型推断 +func demonstrateTypeInference() { + fmt.Println("3. 类型推断演示:") + + // Go 可以根据赋值自动推断类型 + var a = 42 // 推断为 int + var b = 3.14 // 推断为 float64 + var c = "Hello" // 推断为 string + var d = true // 推断为 bool + + // 使用 %T 可以打印变量的类型 + fmt.Printf(" a = %v, 类型: %T\n", a, a) + fmt.Printf(" b = %v, 类型: %T\n", b, b) + fmt.Printf(" c = %v, 类型: %T\n", c, c) + fmt.Printf(" d = %v, 类型: %T\n", d, d) + + // 短变量声明也支持类型推断 + x := 100 // int + y := 2.5 // float64 + z := 'A' // rune (int32) + + fmt.Printf(" x := 100, 类型: %T\n", x) + fmt.Printf(" y := 2.5, 类型: %T\n", y) + fmt.Printf(" z := 'A', 类型: %T, 值: %d\n", z, z) + + fmt.Println() +} + +// demonstrateMultipleDeclaration 演示多变量声明 +func demonstrateMultipleDeclaration() { + fmt.Println("4. 多变量声明:") + + // 方式1: 同时声明多个相同类型的变量 + var x, y, z int = 1, 2, 3 + fmt.Printf(" var x, y, z int = 1, 2, 3: %d, %d, %d\n", x, y, z) + + // 方式2: 同时声明多个不同类型的变量 + var name, age, height = "李四", 30, 180.0 + fmt.Printf(" var name, age, height = ...: %s, %d, %.1f\n", name, age, height) + + // 方式3: 使用短变量声明 + a, b, c := "Go", 1.21, true + fmt.Printf(" a, b, c := ...: %s, %.2f, %t\n", a, b, c) + + // 方式4: 使用括号组织多个变量声明 + var ( + firstName = "王" + lastName = "五" + fullName = firstName + lastName + ) + fmt.Printf(" 组合声明: %s\n", fullName) + + // 变量交换(Go 的特色功能) + m, n := 10, 20 + fmt.Printf(" 交换前: m=%d, n=%d\n", m, n) + m, n = n, m // 交换变量值 + fmt.Printf(" 交换后: m=%d, n=%d\n", m, n) + + fmt.Println() +} + +// demonstrateScope 演示变量作用域 +func demonstrateScope() { + fmt.Println("5. 变量作用域:") + + // 访问全局变量 + fmt.Printf(" 全局变量: %s\n", globalVar) + fmt.Printf(" 包变量: %s, %s, %d\n", packageVar1, packageVar2, packageVar3) + + // 函数级别变量 + funcVar := "函数变量" + fmt.Printf(" 函数变量: %s\n", funcVar) + + // 块级别作用域 + if true { + blockVar := "块变量" + fmt.Printf(" 块变量(在 if 块内): %s\n", blockVar) + + // 可以访问外层变量 + fmt.Printf(" 在块内访问函数变量: %s\n", funcVar) + } + + // blockVar 在这里无法访问,会编译错误 + // fmt.Println(blockVar) // 这行会报错 + + // for 循环的作用域 + for i := 0; i < 3; i++ { + loopVar := fmt.Sprintf("循环变量_%d", i) + fmt.Printf(" %s\n", loopVar) + } + // i 和 loopVar 在这里都无法访问 + + fmt.Println() +} + +// demonstrateAssignment 演示变量赋值和修改 +func demonstrateAssignment() { + fmt.Println("6. 变量赋值和修改:") + + // 基本赋值 + var score int = 85 + fmt.Printf(" 初始分数: %d\n", score) + + // 修改变量值 + score = 90 + fmt.Printf(" 修改后分数: %d\n", score) + + // 复合赋值运算符 + score += 5 // 等同于 score = score + 5 + fmt.Printf(" score += 5: %d\n", score) + + score -= 3 // 等同于 score = score - 3 + fmt.Printf(" score -= 3: %d\n", score) + + score *= 2 // 等同于 score = score * 2 + fmt.Printf(" score *= 2: %d\n", score) + + score /= 4 // 等同于 score = score / 4 + fmt.Printf(" score /= 4: %d\n", score) + + score %= 10 // 等同于 score = score % 10 + fmt.Printf(" score %%= 10: %d\n", score) + + // 自增和自减运算符 + fmt.Printf(" score++ 前: %d\n", score) + score++ // 等同于 score = score + 1 + fmt.Printf(" score++ 后: %d\n", score) + + score-- // 等同于 score = score - 1 + fmt.Printf(" score-- 后: %d\n", score) + + // 注意:Go 中的 ++ 和 -- 是语句,不是表达式 + // 不能写成 x = score++ 这样的形式 + + fmt.Println() +} + +/* +运行这个程序: +go run 02-variables.go + +学习要点: +1. Go 有多种变量声明方式,短变量声明 := 最常用 +2. Go 支持类型推断,可以自动确定变量类型 +3. 每种类型都有零值,未初始化的变量会自动赋予零值 +4. 变量有作用域限制,块内变量无法在块外访问 +5. Go 支持多变量同时声明和赋值 +6. 复合赋值运算符可以简化代码 +7. ++ 和 -- 在 Go 中是语句,不是表达式 + +常见错误: +1. 在包级别使用短变量声明 := (只能在函数内使用) +2. 访问超出作用域的变量 +3. 将 ++ 或 -- 当作表达式使用 +4. 忘记变量的零值概念 +*/ \ No newline at end of file diff --git a/golang-learning/01-basics/03-constants.go b/golang-learning/01-basics/03-constants.go new file mode 100644 index 0000000..bb753bc --- /dev/null +++ b/golang-learning/01-basics/03-constants.go @@ -0,0 +1,302 @@ +/* +03-constants.go - Go 语言常量详解 + +学习目标: +1. 理解常量的概念和作用 +2. 掌握常量声明的方式 +3. 学会使用 iota 枚举器 +4. 了解类型化和无类型化常量 +5. 掌握常量表达式的计算 + +知识点: +- const 关键字 +- 常量组声明 +- iota 枚举器 +- 类型化常量 vs 无类型化常量 +- 常量表达式 +- 预定义常量 +*/ + +package main + +import "fmt" + +// 包级别常量声明 +const PI = 3.14159 +const COMPANY_NAME = "Go 学习公司" + +// 常量组声明 +const ( + // 基本常量 + MAX_SIZE = 100 + MIN_SIZE = 1 + + // 使用表达式的常量 + BUFFER_SIZE = MAX_SIZE * 2 + + // 字符串常量 + VERSION = "1.0.0" + AUTHOR = "Go 学习者" +) + +// 使用 iota 的枚举常量 +const ( + // iota 从 0 开始,每行递增 1 + MONDAY = iota // 0 + TUESDAY // 1 + WEDNESDAY // 2 + THURSDAY // 3 + FRIDAY // 4 + SATURDAY // 5 + SUNDAY // 6 +) + +// 更复杂的 iota 用法 +const ( + _ = iota // 0,使用 _ 忽略第一个值 + KB = 1 << (10 * iota) // 1 << (10 * 1) = 1024 + MB // 1 << (10 * 2) = 1048576 + GB // 1 << (10 * 3) = 1073741824 + TB // 1 << (10 * 4) = 1099511627776 +) + +// 类型化常量 +const ( + MAX_INT int = 2147483647 + MAX_FLOAT float64 = 1.7976931348623157e+308 + IS_ENABLED bool = true +) + +func main() { + fmt.Println("=== Go 语言常量详解 ===\n") + + // 演示基本常量使用 + demonstrateBasicConstants() + + // 演示 iota 枚举器 + demonstrateIota() + + // 演示常量表达式 + demonstrateConstantExpressions() + + // 演示类型化和无类型化常量 + demonstrateTypedConstants() + + // 演示常量的特性 + demonstrateConstantProperties() +} + +// demonstrateBasicConstants 演示基本常量使用 +func demonstrateBasicConstants() { + fmt.Println("1. 基本常量使用:") + + // 使用包级别常量 + fmt.Printf(" 圆周率: %f\n", PI) + fmt.Printf(" 公司名称: %s\n", COMPANY_NAME) + fmt.Printf(" 最大尺寸: %d\n", MAX_SIZE) + fmt.Printf(" 缓冲区大小: %d\n", BUFFER_SIZE) + + // 函数内部常量声明 + const LOCAL_CONST = "这是局部常量" + fmt.Printf(" 局部常量: %s\n", LOCAL_CONST) + + // 常量组声明(函数内部) + const ( + RED = "红色" + GREEN = "绿色" + BLUE = "蓝色" + ) + + fmt.Printf(" 颜色常量: %s, %s, %s\n", RED, GREEN, BLUE) + + fmt.Println() +} + +// demonstrateIota 演示 iota 枚举器 +func demonstrateIota() { + fmt.Println("2. iota 枚举器:") + + // 基本 iota 用法 + fmt.Printf(" 星期枚举:\n") + fmt.Printf(" MONDAY: %d\n", MONDAY) + fmt.Printf(" TUESDAY: %d\n", TUESDAY) + fmt.Printf(" WEDNESDAY: %d\n", WEDNESDAY) + fmt.Printf(" THURSDAY: %d\n", THURSDAY) + fmt.Printf(" FRIDAY: %d\n", FRIDAY) + fmt.Printf(" SATURDAY: %d\n", SATURDAY) + fmt.Printf(" SUNDAY: %d\n", SUNDAY) + + // 存储单位枚举 + fmt.Printf(" 存储单位:\n") + fmt.Printf(" KB: %d 字节\n", KB) + fmt.Printf(" MB: %d 字节\n", MB) + fmt.Printf(" GB: %d 字节\n", GB) + fmt.Printf(" TB: %d 字节\n", TB) + + // 更多 iota 示例 + const ( + A = iota * 2 // 0 * 2 = 0 + B // 1 * 2 = 2 + C // 2 * 2 = 4 + D // 3 * 2 = 6 + ) + + fmt.Printf(" iota 表达式: A=%d, B=%d, C=%d, D=%d\n", A, B, C, D) + + // 跳过某些值 + const ( + E = iota + 1 // 0 + 1 = 1 + F // 1 + 1 = 2 + _ // 2 + 1 = 3 (跳过) + G // 3 + 1 = 4 + ) + + fmt.Printf(" 跳过值: E=%d, F=%d, G=%d\n", E, F, G) + + fmt.Println() +} + +// demonstrateConstantExpressions 演示常量表达式 +func demonstrateConstantExpressions() { + fmt.Println("3. 常量表达式:") + + // 算术表达式 + const ( + A = 10 + B = 20 + SUM = A + B + PRODUCT = A * B + QUOTIENT = B / A + ) + + fmt.Printf(" 算术表达式:\n") + fmt.Printf(" A + B = %d\n", SUM) + fmt.Printf(" A * B = %d\n", PRODUCT) + fmt.Printf(" B / A = %d\n", QUOTIENT) + + // 字符串表达式 + const ( + FIRST_NAME = "张" + LAST_NAME = "三" + FULL_NAME = FIRST_NAME + LAST_NAME + ) + + fmt.Printf(" 字符串表达式: %s\n", FULL_NAME) + + // 布尔表达式 + const ( + X = 5 + Y = 10 + IS_GREATER = X > Y + IS_EQUAL = X == Y + ) + + fmt.Printf(" 布尔表达式:\n") + fmt.Printf(" %d > %d = %t\n", X, Y, IS_GREATER) + fmt.Printf(" %d == %d = %t\n", X, Y, IS_EQUAL) + + fmt.Println() +} + +// demonstrateTypedConstants 演示类型化和无类型化常量 +func demonstrateTypedConstants() { + fmt.Println("4. 类型化和无类型化常量:") + + // 无类型化常量(更灵活) + const UNTYPED_INT = 42 + const UNTYPED_FLOAT = 3.14 + const UNTYPED_STRING = "Hello" + + // 类型化常量(类型固定) + const TYPED_INT int = 42 + const TYPED_FLOAT float64 = 3.14 + const TYPED_STRING string = "Hello" + + fmt.Printf(" 无类型化常量:\n") + fmt.Printf(" UNTYPED_INT 可以赋值给不同的数值类型\n") + + var i8 int8 = UNTYPED_INT // 可以 + var i16 int16 = UNTYPED_INT // 可以 + var i32 int32 = UNTYPED_INT // 可以 + var i64 int64 = UNTYPED_INT // 可以 + + fmt.Printf(" int8: %d, int16: %d, int32: %d, int64: %d\n", i8, i16, i32, i64) + + fmt.Printf(" 类型化常量:\n") + fmt.Printf(" TYPED_INT 只能赋值给相同类型\n") + + var typedVar int = TYPED_INT // 可以,类型匹配 + // var typedVar2 int32 = TYPED_INT // 编译错误,类型不匹配 + + fmt.Printf(" typedVar: %d\n", typedVar) + + // 演示无类型化常量的精度 + const HUGE = 1e1000 // 无类型化常量可以有很高的精度 + fmt.Printf(" 高精度常量: 可以定义超出普通类型范围的常量\n") + + fmt.Println() +} + +// demonstrateConstantProperties 演示常量的特性 +func demonstrateConstantProperties() { + fmt.Println("5. 常量的特性:") + + // 常量在编译时确定 + const COMPILE_TIME = 100 + 200 + fmt.Printf(" 编译时计算: %d\n", COMPILE_TIME) + + // 常量不能修改 + const IMMUTABLE = "不可变" + fmt.Printf(" 不可变性: %s\n", IMMUTABLE) + // IMMUTABLE = "尝试修改" // 编译错误 + + // 常量可以用于数组长度 + const ARRAY_SIZE = 5 + var arr [ARRAY_SIZE]int + fmt.Printf(" 用作数组长度: 数组长度为 %d\n", len(arr)) + + // 预定义常量 + fmt.Printf(" 预定义常量:\n") + fmt.Printf(" true: %t\n", true) + fmt.Printf(" false: %t\n", false) + + // 常量的作用域 + fmt.Printf(" 常量作用域:\n") + fmt.Printf(" 包级别常量在整个包中可见\n") + fmt.Printf(" 函数级别常量只在函数内可见\n") + + // 在块作用域中定义常量 + if true { + const BLOCK_CONST = "块常量" + fmt.Printf(" 块常量: %s\n", BLOCK_CONST) + } + // BLOCK_CONST 在这里不可访问 + + fmt.Println() +} + +/* +运行这个程序: +go run 03-constants.go + +学习要点: +1. 常量使用 const 关键字声明,一旦定义不能修改 +2. 常量在编译时确定值,不能使用运行时才能确定的值 +3. iota 是常量生成器,在 const 块中从 0 开始递增 +4. 无类型化常量比类型化常量更灵活,可以赋值给兼容的类型 +5. 常量可以用于需要编译时常量的地方,如数组长度 +6. 常量表达式在编译时计算,支持算术、字符串、布尔运算 +7. 常量有作用域限制,和变量类似 + +常见用途: +1. 定义配置参数(如缓冲区大小、超时时间) +2. 定义枚举值(如状态码、错误码) +3. 定义数学常数(如 PI、E) +4. 定义字符串常量(如版本号、默认值) + +注意事项: +1. 常量值必须在编译时确定 +2. 不能将函数调用结果赋值给常量 +3. 不能将变量赋值给常量 +4. iota 只在 const 块中有效 +*/ \ No newline at end of file diff --git a/golang-learning/01-basics/04-data-types.go b/golang-learning/01-basics/04-data-types.go new file mode 100644 index 0000000..670d897 --- /dev/null +++ b/golang-learning/01-basics/04-data-types.go @@ -0,0 +1,414 @@ +/* +04-data-types.go - Go 语言数据类型详解 + +学习目标: +1. 掌握 Go 的基本数据类型 +2. 理解不同数值类型的范围和用途 +3. 学会字符串和字符的处理 +4. 了解类型转换的方法 +5. 掌握复合数据类型的基础 + +知识点: +- 整数类型 (int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64) +- 浮点类型 (float32, float64) +- 复数类型 (complex64, complex128) +- 布尔类型 (bool) +- 字符串类型 (string) +- 字符类型 (byte, rune) +- 类型转换 +- 类型别名 +*/ + +package main + +import ( + "fmt" + "math" + "unsafe" +) + +func main() { + fmt.Println("=== Go 语言数据类型详解 ===\n") + + // 演示整数类型 + demonstrateIntegerTypes() + + // 演示浮点类型 + demonstrateFloatTypes() + + // 演示复数类型 + demonstrateComplexTypes() + + // 演示布尔类型 + demonstrateBooleanType() + + // 演示字符串类型 + demonstrateStringType() + + // 演示字符类型 + demonstrateCharacterTypes() + + // 演示类型转换 + demonstrateTypeConversion() + + // 演示类型信息 + demonstrateTypeInfo() +} + +// demonstrateIntegerTypes 演示整数类型 +func demonstrateIntegerTypes() { + fmt.Println("1. 整数类型:") + + // 有符号整数 + var i8 int8 = 127 // -128 到 127 + var i16 int16 = 32767 // -32768 到 32767 + var i32 int32 = 2147483647 // -2^31 到 2^31-1 + var i64 int64 = 9223372036854775807 // -2^63 到 2^63-1 + + fmt.Printf(" 有符号整数:\n") + fmt.Printf(" int8: %d (大小: %d 字节)\n", i8, unsafe.Sizeof(i8)) + fmt.Printf(" int16: %d (大小: %d 字节)\n", i16, unsafe.Sizeof(i16)) + fmt.Printf(" int32: %d (大小: %d 字节)\n", i32, unsafe.Sizeof(i32)) + fmt.Printf(" int64: %d (大小: %d 字节)\n", i64, unsafe.Sizeof(i64)) + + // 无符号整数 + var ui8 uint8 = 255 // 0 到 255 + var ui16 uint16 = 65535 // 0 到 65535 + var ui32 uint32 = 4294967295 // 0 到 2^32-1 + var ui64 uint64 = 18446744073709551615 // 0 到 2^64-1 + + fmt.Printf(" 无符号整数:\n") + fmt.Printf(" uint8: %d (大小: %d 字节)\n", ui8, unsafe.Sizeof(ui8)) + fmt.Printf(" uint16: %d (大小: %d 字节)\n", ui16, unsafe.Sizeof(ui16)) + fmt.Printf(" uint32: %d (大小: %d 字节)\n", ui32, unsafe.Sizeof(ui32)) + fmt.Printf(" uint64: %d (大小: %d 字节)\n", ui64, unsafe.Sizeof(ui64)) + + // 平台相关的整数类型 + var i int = 2147483647 // 32位系统上是int32,64位系统上是int64 + var ui uint = 4294967295 // 32位系统上是uint32,64位系统上是uint64 + var uiptr uintptr = 0x12345678 // 存储指针的整数类型 + + fmt.Printf(" 平台相关类型:\n") + fmt.Printf(" int: %d (大小: %d 字节)\n", i, unsafe.Sizeof(i)) + fmt.Printf(" uint: %d (大小: %d 字节)\n", ui, unsafe.Sizeof(ui)) + fmt.Printf(" uintptr: 0x%x (大小: %d 字节)\n", uiptr, unsafe.Sizeof(uiptr)) + + // 整数的不同表示法 + fmt.Printf(" 整数的不同表示法:\n") + decimal := 42 // 十进制 + binary := 0b101010 // 二进制 (Go 1.13+) + octal := 0o52 // 八进制 (Go 1.13+) + hexadecimal := 0x2A // 十六进制 + + fmt.Printf(" 十进制: %d\n", decimal) + fmt.Printf(" 二进制: %d (0b%b)\n", binary, binary) + fmt.Printf(" 八进制: %d (0o%o)\n", octal, octal) + fmt.Printf(" 十六进制: %d (0x%X)\n", hexadecimal, hexadecimal) + + fmt.Println() +} + +// demonstrateFloatTypes 演示浮点类型 +func demonstrateFloatTypes() { + fmt.Println("2. 浮点类型:") + + // float32 和 float64 + var f32 float32 = 3.14159 + var f64 float64 = 3.141592653589793 + + fmt.Printf(" 基本浮点类型:\n") + fmt.Printf(" float32: %.7f (大小: %d 字节)\n", f32, unsafe.Sizeof(f32)) + fmt.Printf(" float64: %.15f (大小: %d 字节)\n", f64, unsafe.Sizeof(f64)) + + // 浮点数的特殊值 + fmt.Printf(" 特殊浮点值:\n") + fmt.Printf(" 正无穷: %f\n", math.Inf(1)) + fmt.Printf(" 负无穷: %f\n", math.Inf(-1)) + fmt.Printf(" NaN: %f\n", math.NaN()) + + // 浮点数的科学计数法 + scientific1 := 1.23e4 // 1.23 * 10^4 = 12300 + scientific2 := 1.23e-4 // 1.23 * 10^-4 = 0.000123 + + fmt.Printf(" 科学计数法:\n") + fmt.Printf(" 1.23e4 = %f\n", scientific1) + fmt.Printf(" 1.23e-4 = %f\n", scientific2) + + // 浮点数精度问题 + fmt.Printf(" 精度问题演示:\n") + var a float64 = 0.1 + var b float64 = 0.2 + var c float64 = 0.3 + fmt.Printf(" 0.1 + 0.2 = %.17f\n", a+b) + fmt.Printf(" 0.3 = %.17f\n", c) + fmt.Printf(" 0.1 + 0.2 == 0.3: %t\n", a+b == c) + + fmt.Println() +} + +// demonstrateComplexTypes 演示复数类型 +func demonstrateComplexTypes() { + fmt.Println("3. 复数类型:") + + // complex64 和 complex128 + var c64 complex64 = 3 + 4i + var c128 complex128 = 5 + 6i + + fmt.Printf(" 基本复数类型:\n") + fmt.Printf(" complex64: %v (大小: %d 字节)\n", c64, unsafe.Sizeof(c64)) + fmt.Printf(" complex128: %v (大小: %d 字节)\n", c128, unsafe.Sizeof(c128)) + + // 复数的创建方式 + c1 := 1 + 2i // 直接创建 + c2 := complex(3, 4) // 使用 complex 函数 + c3 := complex(float64(5), 6) // 指定类型 + + fmt.Printf(" 复数创建方式:\n") + fmt.Printf(" 直接创建: %v\n", c1) + fmt.Printf(" complex函数: %v\n", c2) + fmt.Printf(" 指定类型: %v\n", c3) + + // 复数的实部和虚部 + fmt.Printf(" 复数的实部和虚部:\n") + fmt.Printf(" %v 的实部: %.1f\n", c2, real(c2)) + fmt.Printf(" %v 的虚部: %.1f\n", c2, imag(c2)) + + // 复数运算 + sum := c1 + c2 + product := c1 * c2 + + fmt.Printf(" 复数运算:\n") + fmt.Printf(" %v + %v = %v\n", c1, c2, sum) + fmt.Printf(" %v * %v = %v\n", c1, c2, product) + + fmt.Println() +} + +// demonstrateBooleanType 演示布尔类型 +func demonstrateBooleanType() { + fmt.Println("4. 布尔类型:") + + var b1 bool = true + var b2 bool = false + var b3 bool // 零值是 false + + fmt.Printf(" 基本布尔值:\n") + fmt.Printf(" b1: %t (大小: %d 字节)\n", b1, unsafe.Sizeof(b1)) + fmt.Printf(" b2: %t\n", b2) + fmt.Printf(" b3 (零值): %t\n", b3) + + // 布尔运算 + fmt.Printf(" 布尔运算:\n") + fmt.Printf(" true && false = %t\n", true && false) + fmt.Printf(" true || false = %t\n", true || false) + fmt.Printf(" !true = %t\n", !true) + fmt.Printf(" !false = %t\n", !false) + + // 比较运算产生布尔值 + x, y := 10, 20 + fmt.Printf(" 比较运算:\n") + fmt.Printf(" %d == %d: %t\n", x, y, x == y) + fmt.Printf(" %d != %d: %t\n", x, y, x != y) + fmt.Printf(" %d < %d: %t\n", x, y, x < y) + fmt.Printf(" %d > %d: %t\n", x, y, x > y) + fmt.Printf(" %d <= %d: %t\n", x, y, x <= y) + fmt.Printf(" %d >= %d: %t\n", x, y, x >= y) + + fmt.Println() +} + +// demonstrateStringType 演示字符串类型 +func demonstrateStringType() { + fmt.Println("5. 字符串类型:") + + var s1 string = "Hello, World!" + var s2 string = "你好,世界!" + var s3 string // 零值是空字符串 "" + + fmt.Printf(" 基本字符串:\n") + fmt.Printf(" s1: \"%s\" (长度: %d, 大小: %d 字节)\n", s1, len(s1), unsafe.Sizeof(s1)) + fmt.Printf(" s2: \"%s\" (长度: %d)\n", s2, len(s2)) + fmt.Printf(" s3 (零值): \"%s\"\n", s3) + + // 字符串是不可变的 + fmt.Printf(" 字符串特性:\n") + fmt.Printf(" 字符串是不可变的(immutable)\n") + fmt.Printf(" 字符串是 UTF-8 编码的\n") + + // 字符串操作 + fmt.Printf(" 字符串操作:\n") + concatenated := s1 + " " + s2 + fmt.Printf(" 连接: \"%s\"\n", concatenated) + + // 原始字符串字面量 + rawString := `这是一个原始字符串 +可以包含换行符 +和 "双引号" 以及 \n 这样的字符` + + fmt.Printf(" 原始字符串:\n") + fmt.Printf(" %s\n", rawString) + + // 字符串转义序列 + escaped := "制表符:\t换行符:\n引号:\"反斜杠:\\" + fmt.Printf(" 转义序列:\n") + fmt.Printf(" %s\n", escaped) + + // 字符串索引和切片 + fmt.Printf(" 字符串索引和切片:\n") + str := "Hello" + fmt.Printf(" str[0]: %c (字节值: %d)\n", str[0], str[0]) + fmt.Printf(" str[1:4]: \"%s\"\n", str[1:4]) + fmt.Printf(" str[:3]: \"%s\"\n", str[:3]) + fmt.Printf(" str[2:]: \"%s\"\n", str[2:]) + + fmt.Println() +} + +// demonstrateCharacterTypes 演示字符类型 +func demonstrateCharacterTypes() { + fmt.Println("6. 字符类型:") + + // byte 类型(uint8 的别名) + var b byte = 'A' + fmt.Printf(" byte 类型:\n") + fmt.Printf(" 字符 'A': %c (ASCII值: %d, 大小: %d 字节)\n", b, b, unsafe.Sizeof(b)) + + // rune 类型(int32 的别名,用于 Unicode 字符) + var r1 rune = 'A' + var r2 rune = '中' + var r3 rune = '🚀' + + fmt.Printf(" rune 类型:\n") + fmt.Printf(" 字符 'A': %c (Unicode值: %d, 大小: %d 字节)\n", r1, r1, unsafe.Sizeof(r1)) + fmt.Printf(" 字符 '中': %c (Unicode值: %d)\n", r2, r2) + fmt.Printf(" 字符 '🚀': %c (Unicode值: %d)\n", r3, r3) + + // 字符串遍历 + fmt.Printf(" 字符串遍历:\n") + str := "Hello世界" + + fmt.Printf(" 按字节遍历:\n") + for i := 0; i < len(str); i++ { + fmt.Printf(" [%d]: %c (%d)\n", i, str[i], str[i]) + } + + fmt.Printf(" 按字符遍历 (range):\n") + for i, r := range str { + fmt.Printf(" [%d]: %c (%d)\n", i, r, r) + } + + // Unicode 转义 + fmt.Printf(" Unicode 转义:\n") + unicode1 := '\u4e2d' // 中 + unicode2 := '\U0001F680' // 🚀 + fmt.Printf(" \\u4e2d: %c\n", unicode1) + fmt.Printf(" \\U0001F680: %c\n", unicode2) + + fmt.Println() +} + +// demonstrateTypeConversion 演示类型转换 +func demonstrateTypeConversion() { + fmt.Println("7. 类型转换:") + + // 数值类型转换 + var i int = 42 + var f float64 = float64(i) // int 转 float64 + var ui uint = uint(i) // int 转 uint + + fmt.Printf(" 数值类型转换:\n") + fmt.Printf(" int %d -> float64 %.1f\n", i, f) + fmt.Printf(" int %d -> uint %d\n", i, ui) + + // 注意:Go 不支持隐式类型转换 + var i32 int32 = 100 + var i64 int64 = int64(i32) // 必须显式转换 + fmt.Printf(" int32 %d -> int64 %d\n", i32, i64) + + // 字符串和数值转换需要使用 strconv 包 + // 这里只演示字符和数值的转换 + var ch byte = 65 + var chStr string = string(ch) + fmt.Printf(" 字符转换:\n") + fmt.Printf(" byte %d -> string \"%s\"\n", ch, chStr) + + var r rune = 20013 // '中' 的 Unicode 值 + var rStr string = string(r) + fmt.Printf(" rune %d -> string \"%s\"\n", r, rStr) + + // 字符串转字节切片和字符切片 + str := "Hello世界" + bytes := []byte(str) + runes := []rune(str) + + fmt.Printf(" 字符串转换:\n") + fmt.Printf(" string -> []byte: %v\n", bytes) + fmt.Printf(" string -> []rune: %v\n", runes) + fmt.Printf(" []byte -> string: \"%s\"\n", string(bytes)) + fmt.Printf(" []rune -> string: \"%s\"\n", string(runes)) + + fmt.Println() +} + +// demonstrateTypeInfo 演示类型信息 +func demonstrateTypeInfo() { + fmt.Println("8. 类型信息:") + + // 使用 %T 打印类型信息 + var i int = 42 + var f float64 = 3.14 + var s string = "Hello" + var b bool = true + var c complex128 = 1 + 2i + + fmt.Printf(" 类型信息:\n") + fmt.Printf(" %v 的类型: %T\n", i, i) + fmt.Printf(" %v 的类型: %T\n", f, f) + fmt.Printf(" \"%v\" 的类型: %T\n", s, s) + fmt.Printf(" %v 的类型: %T\n", b, b) + fmt.Printf(" %v 的类型: %T\n", c, c) + + // 类型别名 + type MyInt int + type MyString string + + var mi MyInt = 100 + var ms MyString = "自定义类型" + + fmt.Printf(" 自定义类型:\n") + fmt.Printf(" %v 的类型: %T\n", mi, mi) + fmt.Printf(" \"%v\" 的类型: %T\n", ms, ms) + + // 类型别名和原类型的转换 + var normalInt int = int(mi) // 需要显式转换 + fmt.Printf(" MyInt -> int: %d\n", normalInt) + + fmt.Println() +} + +/* +运行这个程序: +go run 04-data-types.go + +学习要点: +1. Go 有丰富的基本数据类型,包括整数、浮点、复数、布尔、字符串 +2. 整数类型有有符号和无符号之分,大小从 8 位到 64 位 +3. int 和 uint 的大小取决于平台(32位或64位) +4. 浮点数有精度限制,比较时要注意精度问题 +5. 字符串是 UTF-8 编码的,不可变的 +6. byte 用于 ASCII 字符,rune 用于 Unicode 字符 +7. Go 不支持隐式类型转换,必须显式转换 +8. 可以定义类型别名,但需要显式转换 + +选择类型的建议: +1. 整数:一般使用 int,需要特定大小时使用 int8/16/32/64 +2. 浮点:一般使用 float64,性能要求高时使用 float32 +3. 字符:ASCII 字符用 byte,Unicode 字符用 rune +4. 字符串:使用 string,需要修改时转换为 []byte 或 []rune + +注意事项: +1. 不同类型之间不能直接运算,必须转换为相同类型 +2. 浮点数比较要考虑精度问题 +3. 字符串索引访问的是字节,不是字符 +4. 使用 range 遍历字符串可以正确处理 Unicode 字符 +*/ \ No newline at end of file diff --git a/golang-learning/01-basics/05-operators.go b/golang-learning/01-basics/05-operators.go new file mode 100644 index 0000000..8bb4059 --- /dev/null +++ b/golang-learning/01-basics/05-operators.go @@ -0,0 +1,475 @@ +/* +05-operators.go - Go 语言运算符详解 + +学习目标: +1. 掌握算术运算符的使用 +2. 理解比较运算符的规则 +3. 学会逻辑运算符的应用 +4. 了解位运算符的用法 +5. 掌握赋值运算符的使用 +6. 理解运算符的优先级 + +知识点: +- 算术运算符 (+, -, *, /, %, ++, --) +- 比较运算符 (==, !=, <, <=, >, >=) +- 逻辑运算符 (&&, ||, !) +- 位运算符 (&, |, ^, <<, >>) +- 赋值运算符 (=, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=) +- 其他运算符 (&, *, <-) +- 运算符优先级 +*/ + +package main + +import "fmt" + +func main() { + fmt.Println("=== Go 语言运算符详解 ===\n") + + // 演示算术运算符 + demonstrateArithmeticOperators() + + // 演示比较运算符 + demonstrateComparisonOperators() + + // 演示逻辑运算符 + demonstrateLogicalOperators() + + // 演示位运算符 + demonstrateBitwiseOperators() + + // 演示赋值运算符 + demonstrateAssignmentOperators() + + // 演示其他运算符 + demonstrateOtherOperators() + + // 演示运算符优先级 + demonstrateOperatorPrecedence() + + // 演示实际应用示例 + demonstratePracticalExamples() +} + +// demonstrateArithmeticOperators 演示算术运算符 +func demonstrateArithmeticOperators() { + fmt.Println("1. 算术运算符:") + + a, b := 15, 4 + + fmt.Printf(" 基本算术运算 (a=%d, b=%d):\n", a, b) + fmt.Printf(" a + b = %d + %d = %d\n", a, b, a+b) + fmt.Printf(" a - b = %d - %d = %d\n", a, b, a-b) + fmt.Printf(" a * b = %d * %d = %d\n", a, b, a*b) + fmt.Printf(" a / b = %d / %d = %d\n", a, b, a/b) // 整数除法 + fmt.Printf(" a %% b = %d %% %d = %d\n", a, b, a%b) // 取余 + + // 浮点数除法 + fa, fb := 15.0, 4.0 + fmt.Printf(" 浮点数除法:\n") + fmt.Printf(" %.1f / %.1f = %.2f\n", fa, fb, fa/fb) + + // 自增和自减运算符 + fmt.Printf(" 自增和自减运算符:\n") + x := 10 + fmt.Printf(" x = %d\n", x) + x++ // x = x + 1 + fmt.Printf(" x++ 后: %d\n", x) + x-- // x = x - 1 + fmt.Printf(" x-- 后: %d\n", x) + + // 注意:Go 中的 ++ 和 -- 是语句,不是表达式 + fmt.Printf(" 注意: Go 中 ++ 和 -- 是语句,不能用在表达式中\n") + // y := x++ // 编译错误 + // z := ++x // 编译错误,Go 没有前置 ++ + + // 一元运算符 + fmt.Printf(" 一元运算符:\n") + positive := +10 + negative := -10 + fmt.Printf(" +10 = %d\n", positive) + fmt.Printf(" -10 = %d\n", negative) + + fmt.Println() +} + +// demonstrateComparisonOperators 演示比较运算符 +func demonstrateComparisonOperators() { + fmt.Println("2. 比较运算符:") + + a, b := 10, 20 + + fmt.Printf(" 数值比较 (a=%d, b=%d):\n", a, b) + fmt.Printf(" a == b: %d == %d = %t\n", a, b, a == b) + fmt.Printf(" a != b: %d != %d = %t\n", a, b, a != b) + fmt.Printf(" a < b: %d < %d = %t\n", a, b, a < b) + fmt.Printf(" a <= b: %d <= %d = %t\n", a, b, a <= b) + fmt.Printf(" a > b: %d > %d = %t\n", a, b, a > b) + fmt.Printf(" a >= b: %d >= %d = %t\n", a, b, a >= b) + + // 字符串比较 + s1, s2 := "apple", "banana" + fmt.Printf(" 字符串比较 (s1=\"%s\", s2=\"%s\"):\n", s1, s2) + fmt.Printf(" s1 == s2: %t\n", s1 == s2) + fmt.Printf(" s1 < s2: %t (按字典序)\n", s1 < s2) + fmt.Printf(" s1 > s2: %t\n", s1 > s2) + + // 布尔值比较 + bool1, bool2 := true, false + fmt.Printf(" 布尔值比较:\n") + fmt.Printf(" true == false: %t\n", bool1 == bool2) + fmt.Printf(" true != false: %t\n", bool1 != bool2) + + // 注意:不同类型不能直接比较 + fmt.Printf(" 注意: 不同类型不能直接比较,需要类型转换\n") + var i int = 10 + var f float64 = 10.0 + // fmt.Println(i == f) // 编译错误 + fmt.Printf(" int(10) == float64(10.0): %t\n", float64(i) == f) + + fmt.Println() +} + +// demonstrateLogicalOperators 演示逻辑运算符 +func demonstrateLogicalOperators() { + fmt.Println("3. 逻辑运算符:") + + a, b := true, false + + fmt.Printf(" 基本逻辑运算 (a=%t, b=%t):\n", a, b) + fmt.Printf(" a && b: %t && %t = %t (逻辑与)\n", a, b, a && b) + fmt.Printf(" a || b: %t || %t = %t (逻辑或)\n", a, b, a || b) + fmt.Printf(" !a: !%t = %t (逻辑非)\n", a, !a) + fmt.Printf(" !b: !%t = %t\n", b, !b) + + // 真值表 + fmt.Printf(" 逻辑运算真值表:\n") + fmt.Printf(" A | B | A&&B | A||B | !A\n") + fmt.Printf(" ------|-------|-------|-------|------\n") + fmt.Printf(" true | true | %t | %t | %t\n", true && true, true || true, !true) + fmt.Printf(" true | false | %t| %t | %t\n", true && false, true || false, !true) + fmt.Printf(" false | true | %t| %t | %t\n", false && true, false || true, !false) + fmt.Printf(" false | false | %t| %t | %t\n", false && false, false || false, !false) + + // 短路求值 + fmt.Printf(" 短路求值演示:\n") + x, y := 5, 0 + + // && 短路:如果左边是 false,右边不会执行 + fmt.Printf(" 短路与: (x > 10) && (y != 0)\n") + result1 := (x > 10) && (y != 0) + fmt.Printf(" 结果: %t (右边条件不会被检查)\n", result1) + + // || 短路:如果左边是 true,右边不会执行 + fmt.Printf(" 短路或: (x > 0) || (y != 0)\n") + result2 := (x > 0) || (y != 0) + fmt.Printf(" 结果: %t (右边条件不会被检查)\n", result2) + + // 复合逻辑表达式 + age := 25 + hasLicense := true + hasInsurance := false + + canDrive := age >= 18 && hasLicense && hasInsurance + fmt.Printf(" 复合条件判断:\n") + fmt.Printf(" 年龄: %d, 有驾照: %t, 有保险: %t\n", age, hasLicense, hasInsurance) + fmt.Printf(" 可以开车: %t\n", canDrive) + + fmt.Println() +} + +// demonstrateBitwiseOperators 演示位运算符 +func demonstrateBitwiseOperators() { + fmt.Println("4. 位运算符:") + + a, b := 12, 10 // 12 = 1100, 10 = 1010 (二进制) + + fmt.Printf(" 位运算 (a=%d, b=%d):\n", a, b) + fmt.Printf(" a 的二进制: %08b\n", a) + fmt.Printf(" b 的二进制: %08b\n", b) + fmt.Printf(" a & b: %08b = %d (按位与)\n", a & b, a & b) + fmt.Printf(" a | b: %08b = %d (按位或)\n", a | b, a | b) + fmt.Printf(" a ^ b: %08b = %d (按位异或)\n", a ^ b, a ^ b) + fmt.Printf(" ^a: %08b = %d (按位取反)\n", ^a, ^a) + + // 位移运算 + fmt.Printf(" 位移运算:\n") + x := 8 // 1000 (二进制) + fmt.Printf(" x = %d (%08b)\n", x, x) + fmt.Printf(" x << 1: %08b = %d (左移1位)\n", x << 1, x << 1) + fmt.Printf(" x << 2: %08b = %d (左移2位)\n", x << 2, x << 2) + fmt.Printf(" x >> 1: %08b = %d (右移1位)\n", x >> 1, x >> 1) + fmt.Printf(" x >> 2: %08b = %d (右移2位)\n", x >> 2, x >> 2) + + // 位运算的实际应用 + fmt.Printf(" 位运算应用示例:\n") + + // 检查奇偶性 + num := 15 + isEven := (num & 1) == 0 + fmt.Printf(" %d 是偶数: %t (使用 n&1==0 检查)\n", num, isEven) + + // 快速乘除法(2的幂) + fmt.Printf(" 快速乘除法:\n") + fmt.Printf(" %d * 4 = %d << 2 = %d\n", num, num, num << 2) + fmt.Printf(" %d / 4 = %d >> 2 = %d\n", num, num, num >> 2) + + // 设置、清除、切换位 + flags := 0 + fmt.Printf(" 位标志操作:\n") + fmt.Printf(" 初始标志: %08b\n", flags) + + flags |= (1 << 2) // 设置第2位 + fmt.Printf(" 设置第2位: %08b\n", flags) + + flags &^= (1 << 2) // 清除第2位 + fmt.Printf(" 清除第2位: %08b\n", flags) + + flags ^= (1 << 1) // 切换第1位 + fmt.Printf(" 切换第1位: %08b\n", flags) + + fmt.Println() +} + +// demonstrateAssignmentOperators 演示赋值运算符 +func demonstrateAssignmentOperators() { + fmt.Println("5. 赋值运算符:") + + // 基本赋值 + var x int = 10 + fmt.Printf(" 基本赋值: x = %d\n", x) + + // 复合赋值运算符 + fmt.Printf(" 复合赋值运算符:\n") + + x += 5 // x = x + 5 + fmt.Printf(" x += 5: x = %d\n", x) + + x -= 3 // x = x - 3 + fmt.Printf(" x -= 3: x = %d\n", x) + + x *= 2 // x = x * 2 + fmt.Printf(" x *= 2: x = %d\n", x) + + x /= 4 // x = x / 4 + fmt.Printf(" x /= 4: x = %d\n", x) + + x %= 3 // x = x % 3 + fmt.Printf(" x %%= 3: x = %d\n", x) + + // 位运算赋值 + fmt.Printf(" 位运算赋值:\n") + y := 12 // 1100 + fmt.Printf(" y = %d (%04b)\n", y, y) + + y &= 10 // y = y & 10 (1010) + fmt.Printf(" y &= 10: y = %d (%04b)\n", y, y) + + y |= 5 // y = y | 5 (0101) + fmt.Printf(" y |= 5: y = %d (%04b)\n", y, y) + + y ^= 3 // y = y ^ 3 (0011) + fmt.Printf(" y ^= 3: y = %d (%04b)\n", y, y) + + y <<= 1 // y = y << 1 + fmt.Printf(" y <<= 1: y = %d (%04b)\n", y, y) + + y >>= 2 // y = y >> 2 + fmt.Printf(" y >>= 2: y = %d (%04b)\n", y, y) + + // 多重赋值 + fmt.Printf(" 多重赋值:\n") + a, b, c := 1, 2, 3 + fmt.Printf(" a, b, c := 1, 2, 3: a=%d, b=%d, c=%d\n", a, b, c) + + // 交换变量 + a, b = b, a + fmt.Printf(" a, b = b, a: a=%d, b=%d (交换)\n", a, b) + + fmt.Println() +} + +// demonstrateOtherOperators 演示其他运算符 +func demonstrateOtherOperators() { + fmt.Println("6. 其他运算符:") + + // 地址运算符 & + x := 42 + ptr := &x + fmt.Printf(" 地址运算符 &:\n") + fmt.Printf(" x = %d\n", x) + fmt.Printf(" &x = %p (x的地址)\n", ptr) + + // 解引用运算符 * + fmt.Printf(" 解引用运算符 *:\n") + fmt.Printf(" *ptr = %d (ptr指向的值)\n", *ptr) + + // 修改指针指向的值 + *ptr = 100 + fmt.Printf(" 修改 *ptr = 100 后, x = %d\n", x) + + // 通道运算符 <- (这里只是语法演示,详细内容在并发章节) + fmt.Printf(" 通道运算符 <- (语法演示):\n") + ch := make(chan int, 1) + ch <- 42 // 发送值到通道 + value := <-ch // 从通道接收值 + fmt.Printf(" 通道发送和接收: %d\n", value) + + fmt.Println() +} + +// demonstrateOperatorPrecedence 演示运算符优先级 +func demonstrateOperatorPrecedence() { + fmt.Println("7. 运算符优先级:") + + // 算术运算符优先级 + result1 := 2 + 3 * 4 + result2 := (2 + 3) * 4 + fmt.Printf(" 算术运算优先级:\n") + fmt.Printf(" 2 + 3 * 4 = %d (乘法优先)\n", result1) + fmt.Printf(" (2 + 3) * 4 = %d (括号改变优先级)\n", result2) + + // 比较和逻辑运算符优先级 + a, b, c := 5, 10, 15 + result3 := a < b && b < c + result4 := a < b || b > c && c > a + fmt.Printf(" 比较和逻辑运算优先级:\n") + fmt.Printf(" %d < %d && %d < %d = %t\n", a, b, b, c, result3) + fmt.Printf(" %d < %d || %d > %d && %d > %d = %t\n", a, b, b, c, c, a, result4) + + // 位运算符优先级 + x := 6 // 110 + y := 3 // 011 + result5 := x & y | x ^ y + result6 := x & (y | x) ^ y + fmt.Printf(" 位运算优先级:\n") + fmt.Printf(" %d & %d | %d ^ %d = %d\n", x, y, x, y, result5) + fmt.Printf(" %d & (%d | %d) ^ %d = %d\n", x, y, x, y, result6) + + // 运算符优先级表(从高到低) + fmt.Printf(" 运算符优先级表(从高到低):\n") + fmt.Printf(" 1. * / %% << >> & &^\n") + fmt.Printf(" 2. + - | ^\n") + fmt.Printf(" 3. == != < <= > >=\n") + fmt.Printf(" 4. &&\n") + fmt.Printf(" 5. ||\n") + + fmt.Println() +} + +// demonstratePracticalExamples 演示实际应用示例 +func demonstratePracticalExamples() { + fmt.Println("8. 实际应用示例:") + + // 示例1: 计算器功能 + fmt.Printf(" 示例1 - 简单计算器:\n") + num1, num2 := 15.5, 4.2 + operator := "+" + + var result float64 + switch operator { + case "+": + result = num1 + num2 + case "-": + result = num1 - num2 + case "*": + result = num1 * num2 + case "/": + if num2 != 0 { + result = num1 / num2 + } else { + fmt.Printf(" 错误: 除数不能为零\n") + return + } + } + fmt.Printf(" %.1f %s %.1f = %.2f\n", num1, operator, num2, result) + + // 示例2: 判断闰年 + fmt.Printf(" 示例2 - 判断闰年:\n") + year := 2024 + isLeapYear := (year%4 == 0 && year%100 != 0) || (year%400 == 0) + fmt.Printf(" %d年是闰年: %t\n", year, isLeapYear) + + // 示例3: 位掩码操作 + fmt.Printf(" 示例3 - 权限系统 (位掩码):\n") + const ( + READ = 1 << 0 // 001 + WRITE = 1 << 1 // 010 + EXECUTE = 1 << 2 // 100 + ) + + // 设置权限 + permissions := READ | WRITE // 011 + fmt.Printf(" 初始权限: %03b (读:%t, 写:%t, 执行:%t)\n", + permissions, + permissions&READ != 0, + permissions&WRITE != 0, + permissions&EXECUTE != 0) + + // 添加执行权限 + permissions |= EXECUTE // 111 + fmt.Printf(" 添加执行权限: %03b (读:%t, 写:%t, 执行:%t)\n", + permissions, + permissions&READ != 0, + permissions&WRITE != 0, + permissions&EXECUTE != 0) + + // 移除写权限 + permissions &^= WRITE // 101 + fmt.Printf(" 移除写权限: %03b (读:%t, 写:%t, 执行:%t)\n", + permissions, + permissions&READ != 0, + permissions&WRITE != 0, + permissions&EXECUTE != 0) + + // 示例4: 条件表达式模拟 + fmt.Printf(" 示例4 - 条件表达式模拟:\n") + score := 85 + var grade string + + // Go 没有三元运算符,使用 if-else + if score >= 90 { + grade = "A" + } else if score >= 80 { + grade = "B" + } else if score >= 70 { + grade = "C" + } else if score >= 60 { + grade = "D" + } else { + grade = "F" + } + + fmt.Printf(" 分数 %d 对应等级: %s\n", score, grade) + + fmt.Println() +} + +/* +运行这个程序: +go run 05-operators.go + +学习要点: +1. Go 支持丰富的运算符,包括算术、比较、逻辑、位运算等 +2. ++ 和 -- 在 Go 中是语句,不是表达式,不能用在赋值中 +3. Go 不支持隐式类型转换,不同类型不能直接比较或运算 +4. 逻辑运算符支持短路求值,可以提高效率和安全性 +5. 位运算符在系统编程和性能优化中很有用 +6. 复合赋值运算符可以简化代码 +7. 运算符有优先级,使用括号可以改变优先级 +8. Go 没有三元运算符,使用 if-else 代替 + +实际应用: +1. 算术运算符用于数学计算 +2. 比较运算符用于条件判断 +3. 逻辑运算符用于复合条件 +4. 位运算符用于标志位操作、权限系统等 +5. 赋值运算符用于变量更新 + +注意事项: +1. 除法运算要注意整数除法和浮点除法的区别 +2. 取余运算的结果符号与被除数相同 +3. 位运算时要注意数据类型的位数 +4. 使用逻辑运算符时要注意短路求值的特性 +5. 复杂表达式建议使用括号明确优先级 +*/ \ No newline at end of file diff --git a/golang-learning/01-basics/README.md b/golang-learning/01-basics/README.md new file mode 100644 index 0000000..6cd09ba --- /dev/null +++ b/golang-learning/01-basics/README.md @@ -0,0 +1,23 @@ +# 第一章:基础语法 + +本章将介绍 Go 语言的基础语法,包括程序结构、变量、常量、数据类型和运算符。 + +## 学习目标 +- 理解 Go 程序的基本结构 +- 掌握变量声明和初始化的方法 +- 了解 Go 的基本数据类型 +- 学会使用各种运算符 + +## 文件列表 +- `01-hello-world.go` - Hello World 程序和基本结构 +- `02-variables.go` - 变量声明和初始化 +- `03-constants.go` - 常量定义和使用 +- `04-data-types.go` - 基本数据类型 +- `05-operators.go` - 运算符使用 + +## 运行示例 +```bash +go run 01-hello-world.go +go run 02-variables.go +# ... 依此类推 +``` \ No newline at end of file diff --git a/golang-learning/02-control-flow/01-if-else.go b/golang-learning/02-control-flow/01-if-else.go new file mode 100644 index 0000000..2e7fa29 --- /dev/null +++ b/golang-learning/02-control-flow/01-if-else.go @@ -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. 业务逻辑分支 +*/ \ No newline at end of file diff --git a/golang-learning/02-control-flow/02-switch.go b/golang-learning/02-control-flow/02-switch.go new file mode 100644 index 0000000..f28b22b --- /dev/null +++ b/golang-learning/02-control-flow/02-switch.go @@ -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. 类型判断和处理 +*/ \ No newline at end of file diff --git a/golang-learning/02-control-flow/03-for-loops.go b/golang-learning/02-control-flow/03-for-loops.go new file mode 100644 index 0000000..b4161d4 --- /dev/null +++ b/golang-learning/02-control-flow/03-for-loops.go @@ -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 +*/ \ No newline at end of file diff --git a/golang-learning/02-control-flow/04-range.go b/golang-learning/02-control-flow/04-range.go new file mode 100644 index 0000000..9472dfe --- /dev/null +++ b/golang-learning/02-control-flow/04-range.go @@ -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. 集合操作 +*/ \ No newline at end of file diff --git a/golang-learning/02-control-flow/README.md b/golang-learning/02-control-flow/README.md new file mode 100644 index 0000000..2394425 --- /dev/null +++ b/golang-learning/02-control-flow/README.md @@ -0,0 +1,15 @@ +# 第二章:控制流程 + +本章将学习 Go 语言的控制流程语句,包括条件判断、分支选择和循环结构。 + +## 学习目标 +- 掌握条件语句的使用 +- 理解 switch 语句的特点 +- 学会使用各种形式的 for 循环 +- 了解 range 关键字的用法 + +## 文件列表 +- `01-if-else.go` - 条件判断语句 +- `02-switch.go` - 分支选择语句 +- `03-for-loops.go` - 循环语句 +- `04-range.go` - 范围遍历 \ No newline at end of file diff --git a/golang-learning/03-functions/01-basic-functions.go b/golang-learning/03-functions/01-basic-functions.go new file mode 100644 index 0000000..a1533cd --- /dev/null +++ b/golang-learning/03-functions/01-basic-functions.go @@ -0,0 +1,722 @@ +/* +01-basic-functions.go - Go 语言基础函数详解 + +学习目标: +1. 掌握函数的基本语法和定义 +2. 理解函数参数和返回值 +3. 学会函数的调用方式 +4. 了解函数的作用域规则 +5. 掌握函数的实际应用 + +知识点: +- 函数定义语法 +- 参数传递(值传递) +- 返回值 +- 函数调用 +- 函数作为值 +- 匿名函数 +- 递归函数 +- 函数作用域 +*/ + +package main + +import ( + "fmt" + "math" + "strings" +) + +func main() { + fmt.Println("=== Go 语言基础函数详解 ===\n") + + // 演示基本函数定义和调用 + demonstrateBasicFunctions() + + // 演示函数参数 + demonstrateFunctionParameters() + + // 演示函数返回值 + demonstrateFunctionReturns() + + // 演示函数作为值 + demonstrateFunctionAsValue() + + // 演示匿名函数 + demonstrateAnonymousFunctions() + + // 演示递归函数 + demonstrateRecursiveFunctions() + + // 演示函数作用域 + demonstrateFunctionScope() + + // 演示实际应用示例 + demonstratePracticalExamples() +} + +// demonstrateBasicFunctions 演示基本函数定义和调用 +func demonstrateBasicFunctions() { + fmt.Println("1. 基本函数定义和调用:") + + // 调用无参数无返回值的函数 + fmt.Printf(" 调用无参数无返回值的函数:\n") + sayHello() + + // 调用有参数无返回值的函数 + fmt.Printf(" 调用有参数无返回值的函数:\n") + greetPerson("Alice") + greetPerson("Bob") + + // 调用有参数有返回值的函数 + fmt.Printf(" 调用有参数有返回值的函数:\n") + result := add(10, 20) + fmt.Printf(" add(10, 20) = %d\n", result) + + // 直接在表达式中使用函数调用 + fmt.Printf(" add(5, 7) * 2 = %d\n", add(5, 7)*2) + + // 函数调用作为参数 + fmt.Printf(" add(add(1, 2), add(3, 4)) = %d\n", add(add(1, 2), add(3, 4))) + + fmt.Println() +} + +// demonstrateFunctionParameters 演示函数参数 +func demonstrateFunctionParameters() { + fmt.Println("2. 函数参数:") + + // 单个参数 + fmt.Printf(" 单个参数:\n") + square := calculateSquare(5) + fmt.Printf(" calculateSquare(5) = %d\n", square) + + // 多个参数 + fmt.Printf(" 多个参数:\n") + area := calculateRectangleArea(4, 6) + fmt.Printf(" calculateRectangleArea(4, 6) = %d\n", area) + + // 相同类型的多个参数 + fmt.Printf(" 相同类型的多个参数:\n") + max := findMax(15, 8, 23, 4, 19) + fmt.Printf(" findMax(15, 8, 23, 4, 19) = %d\n", max) + + // 不同类型的参数 + fmt.Printf(" 不同类型的参数:\n") + info := formatPersonInfo("Charlie", 25, 175.5) + fmt.Printf(" %s\n", info) + + // 参数是值传递 + fmt.Printf(" 参数是值传递(不会修改原变量):\n") + x := 10 + fmt.Printf(" 修改前: x = %d\n", x) + tryToModify(x) + fmt.Printf(" 修改后: x = %d (未改变)\n", x) + + // 传递切片(引用类型) + fmt.Printf(" 传递切片(引用类型):\n") + numbers := []int{1, 2, 3, 4, 5} + fmt.Printf(" 修改前: %v\n", numbers) + modifySlice(numbers) + fmt.Printf(" 修改后: %v (已改变)\n", numbers) + + fmt.Println() +} + +// demonstrateFunctionReturns 演示函数返回值 +func demonstrateFunctionReturns() { + fmt.Println("3. 函数返回值:") + + // 单个返回值 + fmt.Printf(" 单个返回值:\n") + length := getStringLength("Hello, World!") + fmt.Printf(" 字符串长度: %d\n", length) + + // 多个返回值 + fmt.Printf(" 多个返回值:\n") + quotient, remainder := divide(17, 5) + fmt.Printf(" 17 ÷ 5 = %d 余 %d\n", quotient, remainder) + + // 命名返回值 + fmt.Printf(" 命名返回值:\n") + min, max := findMinMax([]int{3, 7, 1, 9, 4, 6}) + fmt.Printf(" 数组 [3, 7, 1, 9, 4, 6] 的最小值: %d, 最大值: %d\n", min, max) + + // 忽略某些返回值 + fmt.Printf(" 忽略某些返回值:\n") + _, rem := divide(20, 3) + fmt.Printf(" 20 ÷ 3 的余数: %d\n", rem) + + // 返回函数 + fmt.Printf(" 返回函数:\n") + multiplier := getMultiplier(3) + result := multiplier(10) + fmt.Printf(" 3倍数函数应用于10: %d\n", result) + + fmt.Println() +} + +// demonstrateFunctionAsValue 演示函数作为值 +func demonstrateFunctionAsValue() { + fmt.Println("4. 函数作为值:") + + // 将函数赋值给变量 + fmt.Printf(" 将函数赋值给变量:\n") + var operation func(int, int) int + operation = add + fmt.Printf(" operation = add; operation(5, 3) = %d\n", operation(5, 3)) + + operation = multiply + fmt.Printf(" operation = multiply; operation(5, 3) = %d\n", operation(5, 3)) + + // 函数作为参数 + fmt.Printf(" 函数作为参数:\n") + numbers := []int{1, 2, 3, 4, 5} + + result1 := applyOperation(numbers, double) + fmt.Printf(" 应用 double 函数: %v -> %v\n", numbers, result1) + + result2 := applyOperation(numbers, square) + fmt.Printf(" 应用 square 函数: %v -> %v\n", numbers, result2) + + // 函数切片 + fmt.Printf(" 函数切片:\n") + operations := []func(int, int) int{add, subtract, multiply} + operationNames := []string{"加法", "减法", "乘法"} + + a, b := 12, 4 + for i, op := range operations { + result := op(a, b) + fmt.Printf(" %s: %d %s %d = %d\n", operationNames[i], a, getOperatorSymbol(i), b, result) + } + + fmt.Println() +} + +// demonstrateAnonymousFunctions 演示匿名函数 +func demonstrateAnonymousFunctions() { + fmt.Println("5. 匿名函数:") + + // 基本匿名函数 + fmt.Printf(" 基本匿名函数:\n") + result := func(x, y int) int { + return x*x + y*y + }(3, 4) + fmt.Printf(" 匿名函数计算 3² + 4² = %d\n", result) + + // 将匿名函数赋值给变量 + fmt.Printf(" 将匿名函数赋值给变量:\n") + isEven := func(n int) bool { + return n%2 == 0 + } + + for i := 1; i <= 5; i++ { + fmt.Printf(" %d 是偶数: %t\n", i, isEven(i)) + } + + // 匿名函数作为参数 + fmt.Printf(" 匿名函数作为参数:\n") + numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + + evenNumbers := filter(numbers, func(n int) bool { + return n%2 == 0 + }) + fmt.Printf(" 偶数: %v\n", evenNumbers) + + largeNumbers := filter(numbers, func(n int) bool { + return n > 5 + }) + fmt.Printf(" 大于5的数: %v\n", largeNumbers) + + // 匿名函数闭包 + fmt.Printf(" 匿名函数闭包:\n") + counter := func() func() int { + count := 0 + return func() int { + count++ + return count + } + }() + + fmt.Printf(" 计数器调用1: %d\n", counter()) + fmt.Printf(" 计数器调用2: %d\n", counter()) + fmt.Printf(" 计数器调用3: %d\n", counter()) + + fmt.Println() +} + +// demonstrateRecursiveFunctions 演示递归函数 +func demonstrateRecursiveFunctions() { + fmt.Println("6. 递归函数:") + + // 阶乘函数 + fmt.Printf(" 阶乘函数:\n") + for i := 0; i <= 5; i++ { + fact := factorial(i) + fmt.Printf(" %d! = %d\n", i, fact) + } + + // 斐波那契数列 + fmt.Printf(" 斐波那契数列:\n") + fmt.Printf(" 前10个斐波那契数: ") + for i := 0; i < 10; i++ { + fmt.Printf("%d ", fibonacci(i)) + } + fmt.Printf("\n") + + // 二分查找 + fmt.Printf(" 二分查找:\n") + sortedArray := []int{1, 3, 5, 7, 9, 11, 13, 15, 17, 19} + target := 7 + + index := binarySearch(sortedArray, target, 0, len(sortedArray)-1) + if index != -1 { + fmt.Printf(" 在数组 %v 中找到 %d,索引: %d\n", sortedArray, target, index) + } else { + fmt.Printf(" 在数组 %v 中未找到 %d\n", sortedArray, target) + } + + // 计算数字各位数之和 + fmt.Printf(" 计算数字各位数之和:\n") + number := 12345 + digitSum := sumOfDigits(number) + fmt.Printf(" %d 的各位数之和: %d\n", number, digitSum) + + fmt.Println() +} + +// demonstrateFunctionScope 演示函数作用域 +func demonstrateFunctionScope() { + fmt.Println("7. 函数作用域:") + + // 全局变量 + fmt.Printf(" 全局变量: globalVar = %s\n", globalVar) + + // 局部变量 + fmt.Printf(" 局部变量:\n") + localVar := "这是局部变量" + fmt.Printf(" localVar = %s\n", localVar) + + // 函数内部的作用域 + fmt.Printf(" 函数内部的作用域:\n") + testScope() + + // 参数作用域 + fmt.Printf(" 参数作用域:\n") + testParameterScope("参数值") + + // 变量遮蔽 + fmt.Printf(" 变量遮蔽:\n") + testVariableShadowing() + + fmt.Println() +} + +// demonstratePracticalExamples 演示实际应用示例 +func demonstratePracticalExamples() { + fmt.Println("8. 实际应用示例:") + + // 示例1: 数据处理函数 + fmt.Printf(" 示例1 - 学生成绩处理:\n") + scores := []int{85, 92, 78, 96, 88, 73, 91, 87} + + avg := calculateAverage(scores) + fmt.Printf(" 平均分: %.2f\n", avg) + + grade := getLetterGrade(avg) + fmt.Printf(" 等级: %s\n", grade) + + passCount := countPassingScores(scores, 80) + fmt.Printf(" 80分以上人数: %d/%d\n", passCount, len(scores)) + + // 示例2: 字符串处理函数 + fmt.Printf(" 示例2 - 文本处理:\n") + text := "Hello, World! This is a test." + + wordCount := countWords(text) + fmt.Printf(" 文本: \"%s\"\n", text) + fmt.Printf(" 单词数: %d\n", wordCount) + + reversed := reverseString(text) + fmt.Printf(" 反转: \"%s\"\n", reversed) + + isPalindrome := checkPalindrome("racecar") + fmt.Printf(" \"racecar\" 是回文: %t\n", isPalindrome) + + // 示例3: 数学计算函数 + fmt.Printf(" 示例3 - 几何计算:\n") + + circleArea := calculateCircleArea(5.0) + fmt.Printf(" 半径5的圆面积: %.2f\n", circleArea) + + triangleArea := calculateTriangleArea(3.0, 4.0, 5.0) + fmt.Printf(" 边长3,4,5的三角形面积: %.2f\n", triangleArea) + + distance := calculateDistance(0, 0, 3, 4) + fmt.Printf(" 点(0,0)到点(3,4)的距离: %.2f\n", distance) + + // 示例4: 数据验证函数 + fmt.Printf(" 示例4 - 数据验证:\n") + + emails := []string{ + "user@example.com", + "invalid-email", + "test@domain.org", + } + + for _, email := range emails { + isValid := validateEmail(email) + fmt.Printf(" 邮箱 \"%s\" 有效: %t\n", email, isValid) + } + + phone := "138-1234-5678" + isValidPhone := validatePhoneNumber(phone) + fmt.Printf(" 电话 \"%s\" 有效: %t\n", phone, isValidPhone) + + fmt.Println() +} + +// ========== 函数定义 ========== + +// 全局变量 +var globalVar = "全局变量" + +// 无参数无返回值的函数 +func sayHello() { + fmt.Printf(" Hello, World!\n") +} + +// 有参数无返回值的函数 +func greetPerson(name string) { + fmt.Printf(" Hello, %s!\n", name) +} + +// 有参数有返回值的函数 +func add(a, b int) int { + return a + b +} + +// 单个参数函数 +func calculateSquare(n int) int { + return n * n +} + +// 多个参数函数 +func calculateRectangleArea(width, height int) int { + return width * height +} + +// 相同类型多个参数函数 +func findMax(numbers ...int) int { + if len(numbers) == 0 { + return 0 + } + + max := numbers[0] + for _, num := range numbers { + if num > max { + max = num + } + } + return max +} + +// 不同类型参数函数 +func formatPersonInfo(name string, age int, height float64) string { + return fmt.Sprintf("姓名: %s, 年龄: %d, 身高: %.1fcm", name, age, height) +} + +// 尝试修改参数(值传递) +func tryToModify(x int) { + x = 100 + fmt.Printf(" 函数内部: x = %d\n", x) +} + +// 修改切片 +func modifySlice(slice []int) { + if len(slice) > 0 { + slice[0] = 999 + } +} + +// 单个返回值函数 +func getStringLength(s string) int { + return len(s) +} + +// 多个返回值函数 +func divide(a, b int) (int, int) { + return a / b, a % b +} + +// 命名返回值函数 +func findMinMax(numbers []int) (min, max int) { + if len(numbers) == 0 { + return 0, 0 + } + + min, max = numbers[0], numbers[0] + for _, num := range numbers { + if num < min { + min = num + } + if num > max { + max = num + } + } + return // 自动返回命名的返回值 +} + +// 返回函数的函数 +func getMultiplier(factor int) func(int) int { + return func(x int) int { + return x * factor + } +} + +// 基本运算函数 +func multiply(a, b int) int { + return a * b +} + +func subtract(a, b int) int { + return a - b +} + +// 应用操作函数 +func applyOperation(numbers []int, operation func(int) int) []int { + result := make([]int, len(numbers)) + for i, num := range numbers { + result[i] = operation(num) + } + return result +} + +// 操作函数 +func double(x int) int { + return x * 2 +} + +func square(x int) int { + return x * x +} + +// 获取运算符符号 +func getOperatorSymbol(index int) string { + symbols := []string{"+", "-", "×"} + if index < len(symbols) { + return symbols[index] + } + return "?" +} + +// 过滤函数 +func filter(numbers []int, predicate func(int) bool) []int { + var result []int + for _, num := range numbers { + if predicate(num) { + result = append(result, num) + } + } + return result +} + +// 递归函数:阶乘 +func factorial(n int) int { + if n <= 1 { + return 1 + } + return n * factorial(n-1) +} + +// 递归函数:斐波那契 +func fibonacci(n int) int { + if n <= 1 { + return n + } + return fibonacci(n-1) + fibonacci(n-2) +} + +// 递归函数:二分查找 +func binarySearch(arr []int, target, left, right int) int { + if left > right { + return -1 + } + + mid := (left + right) / 2 + if arr[mid] == target { + return mid + } else if arr[mid] > target { + return binarySearch(arr, target, left, mid-1) + } else { + return binarySearch(arr, target, mid+1, right) + } +} + +// 递归函数:数字各位数之和 +func sumOfDigits(n int) int { + if n < 10 { + return n + } + return n%10 + sumOfDigits(n/10) +} + +// 作用域测试函数 +func testScope() { + innerVar := "函数内部变量" + fmt.Printf(" innerVar = %s\n", innerVar) + + if true { + blockVar := "块级变量" + fmt.Printf(" blockVar = %s\n", blockVar) + } + // blockVar 在这里不可访问 +} + +func testParameterScope(param string) { + fmt.Printf(" 参数 param = %s\n", param) + param = "修改后的参数" + fmt.Printf(" 修改后 param = %s\n", param) +} + +func testVariableShadowing() { + x := "外层变量" + fmt.Printf(" 外层 x = %s\n", x) + + if true { + x := "内层变量" // 遮蔽外层变量 + fmt.Printf(" 内层 x = %s\n", x) + } + + fmt.Printf(" 外层 x = %s (未被修改)\n", x) +} + +// 实际应用函数 +func calculateAverage(scores []int) float64 { + if len(scores) == 0 { + return 0 + } + + sum := 0 + for _, score := range scores { + sum += score + } + return float64(sum) / float64(len(scores)) +} + +func getLetterGrade(average float64) string { + switch { + case average >= 90: + return "A" + case average >= 80: + return "B" + case average >= 70: + return "C" + case average >= 60: + return "D" + default: + return "F" + } +} + +func countPassingScores(scores []int, threshold int) int { + count := 0 + for _, score := range scores { + if score >= threshold { + count++ + } + } + return count +} + +func countWords(text string) int { + words := strings.Fields(text) + return len(words) +} + +func reverseString(s string) string { + runes := []rune(s) + for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 { + runes[i], runes[j] = runes[j], runes[i] + } + return string(runes) +} + +func checkPalindrome(s string) bool { + s = strings.ToLower(s) + for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 { + if s[i] != s[j] { + return false + } + } + return true +} + +func calculateCircleArea(radius float64) float64 { + return math.Pi * radius * radius +} + +func calculateTriangleArea(a, b, c float64) float64 { + // 使用海伦公式 + s := (a + b + c) / 2 + return math.Sqrt(s * (s - a) * (s - b) * (s - c)) +} + +func calculateDistance(x1, y1, x2, y2 float64) float64 { + dx := x2 - x1 + dy := y2 - y1 + return math.Sqrt(dx*dx + dy*dy) +} + +func validateEmail(email string) bool { + return strings.Contains(email, "@") && strings.Contains(email, ".") +} + +func validatePhoneNumber(phone string) bool { + // 简单验证:包含数字和连字符 + return strings.Contains(phone, "-") && len(phone) >= 10 +} + +/* +运行这个程序: +go run 01-basic-functions.go + +学习要点: +1. 函数是 Go 程序的基本构建块 +2. 函数定义语法:func 函数名(参数列表) 返回类型 { 函数体 } +3. Go 支持多返回值,这是其特色功能之一 +4. 参数传递是值传递,但引用类型(切片、映射等)传递的是引用 +5. 函数可以作为值传递和赋值 +6. 支持匿名函数和闭包 +7. 递归函数需要有明确的终止条件 + +函数的组成部分: +1. func 关键字 +2. 函数名 +3. 参数列表(可选) +4. 返回类型(可选) +5. 函数体 + +函数特性: +1. 支持多返回值 +2. 支持命名返回值 +3. 函数是一等公民(可以作为值) +4. 支持匿名函数和闭包 +5. 支持递归调用 + +最佳实践: +1. 函数名应该清晰表达功能 +2. 保持函数简短和专注 +3. 合理使用多返回值 +4. 适当使用命名返回值提高可读性 +5. 避免过深的递归调用 +6. 考虑函数的副作用 + +常见应用场景: +1. 代码复用和模块化 +2. 数据处理和计算 +3. 输入验证和格式化 +4. 算法实现 +5. 业务逻辑封装 +6. 工具函数库 +*/ \ No newline at end of file diff --git a/golang-learning/03-functions/02-multiple-returns.go b/golang-learning/03-functions/02-multiple-returns.go new file mode 100644 index 0000000..394b9c6 --- /dev/null +++ b/golang-learning/03-functions/02-multiple-returns.go @@ -0,0 +1,774 @@ +/* +02-multiple-returns.go - Go 语言多返回值详解 + +学习目标: +1. 掌握多返回值的语法和用法 +2. 理解命名返回值的优势 +3. 学会错误处理的惯用模式 +4. 了解多返回值的实际应用场景 +5. 掌握返回值的最佳实践 + +知识点: +- 多返回值语法 +- 命名返回值 +- 错误处理模式 +- 返回值解构 +- 忽略返回值 +- 多返回值的性能考虑 +- 实际应用场景 +*/ + +package main + +import ( + "errors" + "fmt" + "math" + "strconv" + "strings" + "time" +) + +func main() { + fmt.Println("=== Go 语言多返回值详解 ===\n") + + // 演示基本多返回值 + demonstrateBasicMultipleReturns() + + // 演示命名返回值 + demonstrateNamedReturns() + + // 演示错误处理模式 + demonstrateErrorHandling() + + // 演示返回值解构和忽略 + demonstrateReturnValueHandling() + + // 演示多返回值的实际应用 + demonstratePracticalApplications() + + // 演示多返回值的高级用法 + demonstrateAdvancedUsage() + + // 演示性能考虑 + demonstratePerformanceConsiderations() +} + +// demonstrateBasicMultipleReturns 演示基本多返回值 +func demonstrateBasicMultipleReturns() { + fmt.Println("1. 基本多返回值:") + + // 两个返回值 + fmt.Printf(" 两个返回值:\n") + quotient, remainder := divmod(17, 5) + fmt.Printf(" 17 ÷ 5 = %d 余 %d\n", quotient, remainder) + + // 三个返回值 + fmt.Printf(" 三个返回值:\n") + min, max, avg := analyzeNumbers([]int{3, 7, 1, 9, 4, 6}) + fmt.Printf(" 数组 [3, 7, 1, 9, 4, 6] - 最小值: %d, 最大值: %d, 平均值: %.2f\n", min, max, avg) + + // 不同类型的返回值 + fmt.Printf(" 不同类型的返回值:\n") + name, age, height, isStudent := getPersonInfo() + fmt.Printf(" 个人信息 - 姓名: %s, 年龄: %d, 身高: %.1fcm, 学生: %t\n", + name, age, height, isStudent) + + // 返回值和错误 + fmt.Printf(" 返回值和错误:\n") + result, err := safeDivide(10, 2) + if err != nil { + fmt.Printf(" 错误: %v\n", err) + } else { + fmt.Printf(" 10 ÷ 2 = %.2f\n", result) + } + + result, err = safeDivide(10, 0) + if err != nil { + fmt.Printf(" 错误: %v\n", err) + } else { + fmt.Printf(" 10 ÷ 0 = %.2f\n", result) + } + + fmt.Println() +} + +// demonstrateNamedReturns 演示命名返回值 +func demonstrateNamedReturns() { + fmt.Println("2. 命名返回值:") + + // 基本命名返回值 + fmt.Printf(" 基本命名返回值:\n") + area, perimeter := calculateRectangle(5, 3) + fmt.Printf(" 矩形 5×3 - 面积: %d, 周长: %d\n", area, perimeter) + + // 命名返回值的提前返回 + fmt.Printf(" 命名返回值的提前返回:\n") + score, grade, pass := evaluateScore(85) + fmt.Printf(" 分数 85 - 等级: %s, 是否及格: %t\n", grade, pass) + + score, grade, pass = evaluateScore(45) + fmt.Printf(" 分数 45 - 等级: %s, 是否及格: %t\n", grade, pass) + + // 复杂的命名返回值 + fmt.Printf(" 复杂的命名返回值:\n") + valid, reason, suggestions := validatePassword("123") + fmt.Printf(" 密码 \"123\" - 有效: %t, 原因: %s\n", valid, reason) + if len(suggestions) > 0 { + fmt.Printf(" 建议: %v\n", suggestions) + } + + valid, reason, suggestions = validatePassword("SecurePass123!") + fmt.Printf(" 密码 \"SecurePass123!\" - 有效: %t, 原因: %s\n", valid, reason) + + fmt.Println() +} + +// demonstrateErrorHandling 演示错误处理模式 +func demonstrateErrorHandling() { + fmt.Println("3. 错误处理模式:") + + // 标准错误处理模式 + fmt.Printf(" 标准错误处理模式:\n") + + // 字符串转整数 + value, err := parseInteger("123") + if err != nil { + fmt.Printf(" 解析错误: %v\n", err) + } else { + fmt.Printf(" 解析成功: %d\n", value) + } + + value, err = parseInteger("abc") + if err != nil { + fmt.Printf(" 解析错误: %v\n", err) + } else { + fmt.Printf(" 解析成功: %d\n", value) + } + + // 文件操作模拟 + fmt.Printf(" 文件操作模拟:\n") + content, err := readFile("config.txt") + if err != nil { + fmt.Printf(" 读取文件错误: %v\n", err) + } else { + fmt.Printf(" 文件内容: %s\n", content) + } + + // 网络请求模拟 + fmt.Printf(" 网络请求模拟:\n") + data, statusCode, err := httpGet("https://api.example.com/users") + if err != nil { + fmt.Printf(" 请求错误: %v\n", err) + } else { + fmt.Printf(" 状态码: %d, 数据长度: %d\n", statusCode, len(data)) + } + + // 多层错误处理 + fmt.Printf(" 多层错误处理:\n") + result, err := processUserData("user123") + if err != nil { + fmt.Printf(" 处理用户数据错误: %v\n", err) + } else { + fmt.Printf(" 处理结果: %s\n", result) + } + + fmt.Println() +} + +// demonstrateReturnValueHandling 演示返回值解构和忽略 +func demonstrateReturnValueHandling() { + fmt.Println("4. 返回值解构和忽略:") + + // 接收所有返回值 + fmt.Printf(" 接收所有返回值:\n") + x, y, z := getCoordinates() + fmt.Printf(" 坐标: (%d, %d, %d)\n", x, y, z) + + // 忽略某些返回值 + fmt.Printf(" 忽略某些返回值:\n") + _, _, avgZ := getCoordinates() + fmt.Printf(" 只关心 Z 坐标: %d\n", avgZ) + + // 只检查错误 + fmt.Printf(" 只检查错误:\n") + _, err := safeDivide(10, 2) + if err != nil { + fmt.Printf(" 操作失败: %v\n", err) + } else { + fmt.Printf(" 操作成功\n") + } + + // 链式调用 + fmt.Printf(" 链式调用:\n") + result, err := processChain("input") + if err != nil { + fmt.Printf(" 链式处理错误: %v\n", err) + } else { + fmt.Printf(" 链式处理结果: %s\n", result) + } + + // 多重赋值 + fmt.Printf(" 多重赋值:\n") + a, b := 10, 20 + fmt.Printf(" 交换前: a=%d, b=%d\n", a, b) + a, b = swap(a, b) + fmt.Printf(" 交换后: a=%d, b=%d\n", a, b) + + fmt.Println() +} + +// demonstratePracticalApplications 演示多返回值的实际应用 +func demonstratePracticalApplications() { + fmt.Println("5. 多返回值的实际应用:") + + // 应用1: 数据库查询模拟 + fmt.Printf(" 应用1 - 数据库查询模拟:\n") + user, found, err := findUserByID(123) + if err != nil { + fmt.Printf(" 查询错误: %v\n", err) + } else if !found { + fmt.Printf(" 用户不存在\n") + } else { + fmt.Printf(" 找到用户: %+v\n", user) + } + + // 应用2: 缓存操作 + fmt.Printf(" 应用2 - 缓存操作:\n") + value, hit, err := getFromCache("user:123") + if err != nil { + fmt.Printf(" 缓存错误: %v\n", err) + } else if hit { + fmt.Printf(" 缓存命中: %s\n", value) + } else { + fmt.Printf(" 缓存未命中\n") + } + + // 应用3: 配置解析 + fmt.Printf(" 应用3 - 配置解析:\n") + config, warnings, err := parseConfig("app.conf") + if err != nil { + fmt.Printf(" 配置解析错误: %v\n", err) + } else { + fmt.Printf(" 配置加载成功: %+v\n", config) + if len(warnings) > 0 { + fmt.Printf(" 警告: %v\n", warnings) + } + } + + // 应用4: 数据验证 + fmt.Printf(" 应用4 - 数据验证:\n") + userData := map[string]string{ + "name": "Alice", + "email": "alice@example.com", + "age": "25", + } + + valid, errors := validateUserData(userData) + fmt.Printf(" 用户数据验证 - 有效: %t\n", valid) + if len(errors) > 0 { + fmt.Printf(" 验证错误: %v\n", errors) + } + + // 应用5: 统计分析 + fmt.Printf(" 应用5 - 统计分析:\n") + data := []float64{1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0} + mean, median, stddev := calculateStatistics(data) + fmt.Printf(" 数据: %v\n", data) + fmt.Printf(" 统计结果 - 平均值: %.2f, 中位数: %.2f, 标准差: %.2f\n", + mean, median, stddev) + + fmt.Println() +} + +// demonstrateAdvancedUsage 演示多返回值的高级用法 +func demonstrateAdvancedUsage() { + fmt.Println("6. 多返回值的高级用法:") + + // 返回函数 + fmt.Printf(" 返回函数:\n") + add, multiply := getMathOperations() + fmt.Printf(" add(5, 3) = %d\n", add(5, 3)) + fmt.Printf(" multiply(5, 3) = %d\n", multiply(5, 3)) + + // 返回接口 + fmt.Printf(" 返回接口:\n") + reader, writer := getIOOperations() + data := []byte("Hello, World!") + + n, err := writer.Write(data) + if err != nil { + fmt.Printf(" 写入错误: %v\n", err) + } else { + fmt.Printf(" 写入 %d 字节\n", n) + } + + buffer := make([]byte, 13) + n, err = reader.Read(buffer) + if err != nil { + fmt.Printf(" 读取错误: %v\n", err) + } else { + fmt.Printf(" 读取 %d 字节: %s\n", n, string(buffer[:n])) + } + + // 返回通道 + fmt.Printf(" 返回通道:\n") + input, output := createPipeline() + + // 发送数据 + go func() { + for i := 1; i <= 3; i++ { + input <- i + } + close(input) + }() + + // 接收处理后的数据 + for result := range output { + fmt.Printf(" 处理结果: %d\n", result) + } + + fmt.Println() +} + +// demonstratePerformanceConsiderations 演示性能考虑 +func demonstratePerformanceConsiderations() { + fmt.Println("7. 性能考虑:") + + // 返回值的内存分配 + fmt.Printf(" 返回值的内存分配:\n") + + // 返回值拷贝 vs 返回指针 + largeData := make([]int, 1000) + for i := range largeData { + largeData[i] = i + } + + // 返回拷贝(可能影响性能) + copied, size := copyLargeData(largeData) + fmt.Printf(" 返回拷贝 - 大小: %d, 第一个元素: %d\n", size, copied[0]) + + // 返回指针(更高效) + ptr, size := referenceLargeData(largeData) + fmt.Printf(" 返回指针 - 大小: %d, 第一个元素: %d\n", size, (*ptr)[0]) + + // 多返回值 vs 结构体 + fmt.Printf(" 多返回值 vs 结构体:\n") + + // 使用多返回值 + name, age, email := getUserInfo1() + fmt.Printf(" 多返回值: %s, %d, %s\n", name, age, email) + + // 使用结构体 + user := getUserInfo2() + fmt.Printf(" 结构体: %s, %d, %s\n", user.Name, user.Age, user.Email) + + // 错误处理的性能 + fmt.Printf(" 错误处理的性能:\n") + + // 正常情况 + start := time.Now() + for i := 0; i < 1000; i++ { + _, err := fastOperation(i) + if err != nil { + // 处理错误 + } + } + duration := time.Since(start) + fmt.Printf(" 1000次正常操作耗时: %v\n", duration) + + fmt.Println() +} + +// ========== 函数定义 ========== + +// 基本多返回值函数 +func divmod(a, b int) (int, int) { + return a / b, a % b +} + +func analyzeNumbers(numbers []int) (int, int, float64) { + if len(numbers) == 0 { + return 0, 0, 0 + } + + min, max := numbers[0], numbers[0] + sum := 0 + + for _, num := range numbers { + if num < min { + min = num + } + if num > max { + max = num + } + sum += num + } + + avg := float64(sum) / float64(len(numbers)) + return min, max, avg +} + +func getPersonInfo() (string, int, float64, bool) { + return "Alice", 25, 165.5, true +} + +func safeDivide(a, b float64) (float64, error) { + if b == 0 { + return 0, errors.New("除数不能为零") + } + return a / b, nil +} + +// 命名返回值函数 +func calculateRectangle(width, height int) (area, perimeter int) { + area = width * height + perimeter = 2 * (width + height) + return // 自动返回命名的返回值 +} + +func evaluateScore(score int) (originalScore int, grade string, pass bool) { + originalScore = score + + if score < 0 || score > 100 { + grade = "无效" + return // 提前返回 + } + + switch { + case score >= 90: + grade = "A" + case score >= 80: + grade = "B" + case score >= 70: + grade = "C" + case score >= 60: + grade = "D" + default: + grade = "F" + } + + pass = score >= 60 + return +} + +func validatePassword(password string) (valid bool, reason string, suggestions []string) { + if len(password) < 8 { + reason = "密码长度不足8位" + suggestions = append(suggestions, "增加密码长度") + return + } + + hasUpper := strings.ContainsAny(password, "ABCDEFGHIJKLMNOPQRSTUVWXYZ") + hasLower := strings.ContainsAny(password, "abcdefghijklmnopqrstuvwxyz") + hasDigit := strings.ContainsAny(password, "0123456789") + hasSpecial := strings.ContainsAny(password, "!@#$%^&*") + + if !hasUpper { + suggestions = append(suggestions, "添加大写字母") + } + if !hasLower { + suggestions = append(suggestions, "添加小写字母") + } + if !hasDigit { + suggestions = append(suggestions, "添加数字") + } + if !hasSpecial { + suggestions = append(suggestions, "添加特殊字符") + } + + if hasUpper && hasLower && hasDigit && hasSpecial { + valid = true + reason = "密码强度良好" + } else { + reason = "密码强度不足" + } + + return +} + +// 错误处理函数 +func parseInteger(s string) (int, error) { + value, err := strconv.Atoi(s) + if err != nil { + return 0, fmt.Errorf("无法解析整数 '%s': %w", s, err) + } + return value, nil +} + +func readFile(filename string) (string, error) { + // 模拟文件读取 + if filename == "config.txt" { + return "server_port=8080\ndebug=true", nil + } + return "", fmt.Errorf("文件 '%s' 不存在", filename) +} + +func httpGet(url string) ([]byte, int, error) { + // 模拟HTTP请求 + if strings.Contains(url, "example.com") { + return []byte(`{"users": [{"id": 1, "name": "Alice"}]}`), 200, nil + } + return nil, 0, errors.New("网络连接失败") +} + +func processUserData(userID string) (string, error) { + // 模拟多层处理 + if userID == "" { + return "", errors.New("用户ID不能为空") + } + + // 模拟数据库查询 + if userID == "user123" { + return "用户数据处理完成", nil + } + + return "", fmt.Errorf("用户 '%s' 不存在", userID) +} + +// 返回值处理函数 +func getCoordinates() (int, int, int) { + return 10, 20, 30 +} + +func processChain(input string) (string, error) { + if input == "" { + return "", errors.New("输入不能为空") + } + + // 模拟处理链 + step1 := strings.ToUpper(input) + step2 := step1 + "_PROCESSED" + + return step2, nil +} + +func swap(a, b int) (int, int) { + return b, a +} + +// 实际应用函数 +type User struct { + ID int + Name string + Email string +} + +func findUserByID(id int) (User, bool, error) { + // 模拟数据库查询 + if id <= 0 { + return User{}, false, errors.New("无效的用户ID") + } + + if id == 123 { + return User{ID: 123, Name: "Alice", Email: "alice@example.com"}, true, nil + } + + return User{}, false, nil +} + +func getFromCache(key string) (string, bool, error) { + // 模拟缓存操作 + cache := map[string]string{ + "user:123": "Alice", + "user:456": "Bob", + } + + if value, exists := cache[key]; exists { + return value, true, nil + } + + return "", false, nil +} + +type Config struct { + Port int + Debug bool + Timeout int +} + +func parseConfig(filename string) (Config, []string, error) { + // 模拟配置解析 + config := Config{Port: 8080, Debug: true, Timeout: 30} + warnings := []string{"使用默认超时值"} + + if filename == "app.conf" { + return config, warnings, nil + } + + return Config{}, nil, fmt.Errorf("配置文件 '%s' 不存在", filename) +} + +func validateUserData(data map[string]string) (bool, []string) { + var errors []string + + if name := data["name"]; name == "" { + errors = append(errors, "姓名不能为空") + } + + if email := data["email"]; !strings.Contains(email, "@") { + errors = append(errors, "邮箱格式无效") + } + + if ageStr := data["age"]; ageStr != "" { + if age, err := strconv.Atoi(ageStr); err != nil || age < 0 || age > 150 { + errors = append(errors, "年龄无效") + } + } + + return len(errors) == 0, errors +} + +func calculateStatistics(data []float64) (mean, median, stddev float64) { + if len(data) == 0 { + return 0, 0, 0 + } + + // 计算平均值 + sum := 0.0 + for _, v := range data { + sum += v + } + mean = sum / float64(len(data)) + + // 计算中位数(简化版) + median = data[len(data)/2] + + // 计算标准差 + variance := 0.0 + for _, v := range data { + variance += (v - mean) * (v - mean) + } + stddev = math.Sqrt(variance / float64(len(data))) + + return +} + +// 高级用法函数 +func getMathOperations() (func(int, int) int, func(int, int) int) { + add := func(a, b int) int { return a + b } + multiply := func(a, b int) int { return a * b } + return add, multiply +} + +type MockReader struct { + data []byte + pos int +} + +func (r *MockReader) Read(p []byte) (n int, error) { + if r.pos >= len(r.data) { + return 0, errors.New("EOF") + } + + n = copy(p, r.data[r.pos:]) + r.pos += n + return n, nil +} + +type MockWriter struct { + data []byte +} + +func (w *MockWriter) Write(p []byte) (n int, error) { + w.data = append(w.data, p...) + return len(p), nil +} + +func getIOOperations() (*MockReader, *MockWriter) { + reader := &MockReader{data: []byte("Hello, World!")} + writer := &MockWriter{} + return reader, writer +} + +func createPipeline() (chan<- int, <-chan int) { + input := make(chan int) + output := make(chan int) + + go func() { + defer close(output) + for value := range input { + output <- value * 2 // 处理数据 + } + }() + + return input, output +} + +// 性能考虑函数 +func copyLargeData(data []int) ([]int, int) { + copied := make([]int, len(data)) + copy(copied, data) + return copied, len(copied) +} + +func referenceLargeData(data []int) (*[]int, int) { + return &data, len(data) +} + +func getUserInfo1() (string, int, string) { + return "Alice", 25, "alice@example.com" +} + +type UserInfo struct { + Name string + Age int + Email string +} + +func getUserInfo2() UserInfo { + return UserInfo{Name: "Alice", Age: 25, Email: "alice@example.com"} +} + +func fastOperation(n int) (int, error) { + if n < 0 { + return 0, errors.New("负数") + } + return n * 2, nil +} + +/* +运行这个程序: +go run 02-multiple-returns.go + +学习要点: +1. Go 支持多返回值,这是其独特且强大的特性 +2. 多返回值常用于返回结果和错误信息 +3. 命名返回值可以提高代码可读性,支持提前返回 +4. 可以使用 _ 忽略不需要的返回值 +5. 多返回值是 Go 错误处理的基础 + +多返回值的优势: +1. 避免使用指针参数传递多个结果 +2. 使错误处理更加明确和一致 +3. 提高代码的可读性和维护性 +4. 支持函数式编程风格 + +常见模式: +1. (result, error) - 标准错误处理模式 +2. (value, ok) - 检查操作是否成功 +3. (value, found, error) - 查询操作模式 +4. 命名返回值 - 提高可读性 + +最佳实践: +1. 错误通常作为最后一个返回值 +2. 使用命名返回值提高复杂函数的可读性 +3. 适当使用 _ 忽略不需要的返回值 +4. 保持返回值数量合理(通常不超过3-4个) +5. 考虑使用结构体替代过多的返回值 + +性能考虑: +1. 多返回值通常比传递指针参数更高效 +2. 大对象考虑返回指针而不是值拷贝 +3. 命名返回值可能有轻微的性能开销 +4. 错误处理的性能影响通常可以忽略 + +应用场景: +1. 错误处理 +2. 数据库查询 +3. 网络操作 +4. 文件操作 +5. 数据验证 +6. 统计计算 +7. 缓存操作 +*/ \ No newline at end of file diff --git a/golang-learning/03-functions/03-variadic-functions.go b/golang-learning/03-functions/03-variadic-functions.go new file mode 100644 index 0000000..3b09ffe --- /dev/null +++ b/golang-learning/03-functions/03-variadic-functions.go @@ -0,0 +1,757 @@ +/* +03-variadic-functions.go - Go 语言可变参数函数详解 + +学习目标: +1. 掌握可变参数函数的语法 +2. 理解可变参数的传递机制 +3. 学会可变参数的实际应用 +4. 了解可变参数的限制和注意事项 +5. 掌握可变参数的最佳实践 + +知识点: +- 可变参数语法 (...type) +- 可变参数的传递和展开 +- 空参数和单参数处理 +- 可变参数与切片的关系 +- 可变参数的类型限制 +- 实际应用场景 +*/ + +package main + +import ( + "fmt" + "strings" +) + +func main() { + fmt.Println("=== Go 语言可变参数函数详解 ===\n") + + // 演示基本可变参数函数 + demonstrateBasicVariadicFunctions() + + // 演示可变参数的传递 + demonstrateVariadicParameterPassing() + + // 演示可变参数与其他参数的组合 + demonstrateVariadicWithOtherParams() + + // 演示可变参数的类型处理 + demonstrateVariadicTypeHandling() + + // 演示可变参数的实际应用 + demonstratePracticalApplications() + + // 演示可变参数的高级用法 + demonstrateAdvancedVariadicUsage() + + // 演示可变参数的限制和注意事项 + demonstrateVariadicLimitations() +} + +// demonstrateBasicVariadicFunctions 演示基本可变参数函数 +func demonstrateBasicVariadicFunctions() { + fmt.Println("1. 基本可变参数函数:") + + // 数字求和 + fmt.Printf(" 数字求和:\n") + fmt.Printf(" sum() = %d\n", sum()) + fmt.Printf(" sum(1) = %d\n", sum(1)) + fmt.Printf(" sum(1, 2, 3) = %d\n", sum(1, 2, 3)) + fmt.Printf(" sum(1, 2, 3, 4, 5) = %d\n", sum(1, 2, 3, 4, 5)) + + // 字符串连接 + fmt.Printf(" 字符串连接:\n") + fmt.Printf(" concat() = \"%s\"\n", concat()) + fmt.Printf(" concat(\"Hello\") = \"%s\"\n", concat("Hello")) + fmt.Printf(" concat(\"Hello\", \" \", \"World\") = \"%s\"\n", + concat("Hello", " ", "World")) + fmt.Printf(" concat(\"Go\", \" is\", \" awesome\", \"!\") = \"%s\"\n", + concat("Go", " is", " awesome", "!")) + + // 找最大值 + fmt.Printf(" 找最大值:\n") + fmt.Printf(" max(1) = %d\n", max(1)) + fmt.Printf(" max(3, 1, 4, 1, 5) = %d\n", max(3, 1, 4, 1, 5)) + fmt.Printf(" max(10, 5, 8, 3, 9, 2, 7) = %d\n", max(10, 5, 8, 3, 9, 2, 7)) + + fmt.Println() +} + +// demonstrateVariadicParameterPassing 演示可变参数的传递 +func demonstrateVariadicParameterPassing() { + fmt.Println("2. 可变参数的传递:") + + // 直接传递多个参数 + fmt.Printf(" 直接传递多个参数:\n") + result1 := multiply(2, 3, 4, 5) + fmt.Printf(" multiply(2, 3, 4, 5) = %d\n", result1) + + // 传递切片(需要展开) + fmt.Printf(" 传递切片(使用 ... 展开):\n") + numbers := []int{2, 3, 4, 5} + result2 := multiply(numbers...) + fmt.Printf(" numbers := %v\n", numbers) + fmt.Printf(" multiply(numbers...) = %d\n", result2) + + // 混合传递 + fmt.Printf(" 混合传递:\n") + result3 := multiply(1, 2) + moreNumbers := []int{3, 4, 5} + result4 := multiply(append([]int{1, 2}, moreNumbers...)...) + fmt.Printf(" multiply(1, 2) = %d\n", result3) + fmt.Printf(" 混合传递结果 = %d\n", result4) + + // 空切片传递 + fmt.Printf(" 空切片传递:\n") + var emptySlice []int + result5 := multiply(emptySlice...) + fmt.Printf(" multiply(emptySlice...) = %d\n", result5) + + // 传递给其他可变参数函数 + fmt.Printf(" 传递给其他可变参数函数:\n") + numbers2 := []int{10, 20, 30} + avg := average(numbers2...) + fmt.Printf(" average(%v) = %.2f\n", numbers2, avg) + + fmt.Println() +} + +// demonstrateVariadicWithOtherParams 演示可变参数与其他参数的组合 +func demonstrateVariadicWithOtherParams() { + fmt.Println("3. 可变参数与其他参数的组合:") + + // 固定参数 + 可变参数 + fmt.Printf(" 固定参数 + 可变参数:\n") + result1 := formatMessage("INFO", "User login", "successful", "from IP 192.168.1.1") + fmt.Printf(" %s\n", result1) + + result2 := formatMessage("ERROR", "Database connection failed") + fmt.Printf(" %s\n", result2) + + // 多个固定参数 + 可变参数 + fmt.Printf(" 多个固定参数 + 可变参数:\n") + result3 := calculateWithOperation("add", 1, 2, 3, 4, 5) + fmt.Printf(" calculateWithOperation(\"add\", 1, 2, 3, 4, 5) = %.2f\n", result3) + + result4 := calculateWithOperation("multiply", 2, 3, 4) + fmt.Printf(" calculateWithOperation(\"multiply\", 2, 3, 4) = %.2f\n", result4) + + result5 := calculateWithOperation("average", 10, 20, 30, 40, 50) + fmt.Printf(" calculateWithOperation(\"average\", 10, 20, 30, 40, 50) = %.2f\n", result5) + + // 带默认值的可变参数函数 + fmt.Printf(" 带默认值的可变参数函数:\n") + config1 := createConfig("myapp") + fmt.Printf(" createConfig(\"myapp\") = %+v\n", config1) + + config2 := createConfig("myapp", "debug=true", "port=8080", "timeout=30") + fmt.Printf(" createConfig with options = %+v\n", config2) + + fmt.Println() +} + +// demonstrateVariadicTypeHandling 演示可变参数的类型处理 +func demonstrateVariadicTypeHandling() { + fmt.Println("4. 可变参数的类型处理:") + + // 不同类型的可变参数 + fmt.Printf(" 字符串可变参数:\n") + joined := joinStrings(", ", "apple", "banana", "cherry", "date") + fmt.Printf(" joinStrings(\", \", \"apple\", \"banana\", \"cherry\", \"date\") = \"%s\"\n", joined) + + // 接口类型的可变参数 + fmt.Printf(" 接口类型的可变参数:\n") + printValues("混合类型:", 42, "hello", 3.14, true, []int{1, 2, 3}) + + // 结构体类型的可变参数 + fmt.Printf(" 结构体类型的可变参数:\n") + person1 := Person{Name: "Alice", Age: 25} + person2 := Person{Name: "Bob", Age: 30} + person3 := Person{Name: "Charlie", Age: 35} + + avgAge := calculateAverageAge(person1, person2, person3) + fmt.Printf(" 平均年龄: %.1f\n", avgAge) + + // 函数类型的可变参数 + fmt.Printf(" 函数类型的可变参数:\n") + add := func(a, b int) int { return a + b } + multiply := func(a, b int) int { return a * b } + subtract := func(a, b int) int { return a - b } + + results := applyOperations(10, 5, add, multiply, subtract) + fmt.Printf(" applyOperations(10, 5, add, multiply, subtract) = %v\n", results) + + fmt.Println() +} + +// demonstratePracticalApplications 演示可变参数的实际应用 +func demonstratePracticalApplications() { + fmt.Println("5. 可变参数的实际应用:") + + // 应用1: 日志记录 + fmt.Printf(" 应用1 - 日志记录:\n") + logInfo("用户登录", "用户ID", 123, "IP地址", "192.168.1.1") + logError("数据库连接失败", "错误码", 1001, "重试次数", 3) + logDebug("缓存命中", "键", "user:123", "值", "Alice") + + // 应用2: SQL 查询构建 + fmt.Printf(" 应用2 - SQL 查询构建:\n") + query1 := buildSelectQuery("users", "name", "email", "age") + fmt.Printf(" %s\n", query1) + + query2 := buildSelectQuery("products", "id", "name", "price", "category", "stock") + fmt.Printf(" %s\n", query2) + + // 应用3: HTTP 路由注册 + fmt.Printf(" 应用3 - HTTP 路由注册:\n") + registerRoute("GET", "/users", authMiddleware, loggingMiddleware, getUsersHandler) + registerRoute("POST", "/users", authMiddleware, validateMiddleware, createUserHandler) + + // 应用4: 数据验证 + fmt.Printf(" 应用4 - 数据验证:\n") + userData := map[string]interface{}{ + "name": "Alice", + "email": "alice@example.com", + "age": 25, + } + + errors := validateData(userData, + validateRequired("name"), + validateEmail("email"), + validateRange("age", 0, 150), + ) + + if len(errors) == 0 { + fmt.Printf(" 数据验证通过\n") + } else { + fmt.Printf(" 验证错误: %v\n", errors) + } + + // 应用5: 配置合并 + fmt.Printf(" 应用5 - 配置合并:\n") + defaultConfig := Config{Port: 8080, Debug: false, Timeout: 30} + userConfig := Config{Debug: true, MaxConnections: 100} + envConfig := Config{Port: 9090, Timeout: 60} + + finalConfig := mergeConfigs(defaultConfig, userConfig, envConfig) + fmt.Printf(" 最终配置: %+v\n", finalConfig) + + fmt.Println() +} + +// demonstrateAdvancedVariadicUsage 演示可变参数的高级用法 +func demonstrateAdvancedVariadicUsage() { + fmt.Println("6. 可变参数的高级用法:") + + // 可变参数的递归处理 + fmt.Printf(" 可变参数的递归处理:\n") + result1 := recursiveSum(1, 2, 3, 4, 5) + fmt.Printf(" recursiveSum(1, 2, 3, 4, 5) = %d\n", result1) + + // 可变参数的函数式处理 + fmt.Printf(" 可变参数的函数式处理:\n") + numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + + evenSum := reduceInts(filterInts(numbers, isEven)...) + fmt.Printf(" 偶数之和: %d\n", evenSum) + + oddProduct := reduceInts(filterInts(numbers, isOdd)...) + fmt.Printf(" 奇数之和: %d\n", oddProduct) + + // 可变参数的管道处理 + fmt.Printf(" 可变参数的管道处理:\n") + pipeline := createPipeline( + func(x int) int { return x * 2 }, // 乘以2 + func(x int) int { return x + 1 }, // 加1 + func(x int) int { return x * x }, // 平方 + ) + + for i := 1; i <= 3; i++ { + result := pipeline(i) + fmt.Printf(" pipeline(%d) = %d\n", i, result) + } + + // 可变参数的选项模式 + fmt.Printf(" 可变参数的选项模式:\n") + server1 := createServer("localhost", + withPort(8080), + withTimeout(30), + withDebug(true), + ) + fmt.Printf(" 服务器1: %+v\n", server1) + + server2 := createServer("0.0.0.0", + withPort(9090), + withMaxConnections(1000), + ) + fmt.Printf(" 服务器2: %+v\n", server2) + + fmt.Println() +} + +// demonstrateVariadicLimitations 演示可变参数的限制和注意事项 +func demonstrateVariadicLimitations() { + fmt.Println("7. 可变参数的限制和注意事项:") + + // 限制1: 可变参数必须是最后一个参数 + fmt.Printf(" 限制1: 可变参数必须是最后一个参数\n") + fmt.Printf(" ✓ func example(a int, b ...string) - 正确\n") + fmt.Printf(" ✗ func example(a ...int, b string) - 错误\n") + + // 限制2: 一个函数只能有一个可变参数 + fmt.Printf(" 限制2: 一个函数只能有一个可变参数\n") + fmt.Printf(" ✗ func example(a ...int, b ...string) - 错误\n") + + // 注意事项1: 可变参数是切片 + fmt.Printf(" 注意事项1: 可变参数在函数内部是切片\n") + inspectVariadicParam(1, 2, 3, 4, 5) + + // 注意事项2: 修改可变参数会影响原始切片 + fmt.Printf(" 注意事项2: 修改可变参数可能影响原始数据\n") + originalSlice := []int{1, 2, 3, 4, 5} + fmt.Printf(" 修改前: %v\n", originalSlice) + modifyVariadicParam(originalSlice...) + fmt.Printf(" 修改后: %v\n", originalSlice) + + // 注意事项3: 性能考虑 + fmt.Printf(" 注意事项3: 性能考虑\n") + fmt.Printf(" - 传递大量参数时,切片展开可能有性能开销\n") + fmt.Printf(" - 考虑直接传递切片而不是可变参数\n") + + // 注意事项4: 类型安全 + fmt.Printf(" 注意事项4: 类型安全\n") + fmt.Printf(" - 可变参数必须是相同类型\n") + fmt.Printf(" - 使用 interface{} 可以接受不同类型,但失去类型安全\n") + + // 最佳实践 + fmt.Printf(" 最佳实践:\n") + fmt.Printf(" 1. 优先考虑切片参数而不是可变参数\n") + fmt.Printf(" 2. 可变参数适用于调用时参数数量不确定的场景\n") + fmt.Printf(" 3. 注意可变参数的性能影响\n") + fmt.Printf(" 4. 使用选项模式处理复杂的可选参数\n") + + fmt.Println() +} + +// ========== 函数定义 ========== + +// 基本可变参数函数 +func sum(numbers ...int) int { + total := 0 + for _, num := range numbers { + total += num + } + return total +} + +func concat(strings ...string) string { + result := "" + for _, str := range strings { + result += str + } + return result +} + +func max(numbers ...int) int { + if len(numbers) == 0 { + return 0 + } + + maximum := numbers[0] + for _, num := range numbers { + if num > maximum { + maximum = num + } + } + return maximum +} + +func multiply(numbers ...int) int { + if len(numbers) == 0 { + return 0 + } + + result := 1 + for _, num := range numbers { + result *= num + } + return result +} + +func average(numbers ...int) float64 { + if len(numbers) == 0 { + return 0 + } + + total := sum(numbers...) + return float64(total) / float64(len(numbers)) +} + +// 固定参数 + 可变参数 +func formatMessage(level string, messages ...string) string { + timestamp := "2024-01-01 12:00:00" + allMessages := strings.Join(messages, " ") + return fmt.Sprintf("[%s] %s: %s", timestamp, level, allMessages) +} + +func calculateWithOperation(operation string, numbers ...int) float64 { + if len(numbers) == 0 { + return 0 + } + + switch operation { + case "add": + return float64(sum(numbers...)) + case "multiply": + return float64(multiply(numbers...)) + case "average": + return average(numbers...) + default: + return 0 + } +} + +type AppConfig struct { + Name string + Options map[string]string +} + +func createConfig(name string, options ...string) AppConfig { + config := AppConfig{ + Name: name, + Options: make(map[string]string), + } + + for _, option := range options { + parts := strings.SplitN(option, "=", 2) + if len(parts) == 2 { + config.Options[parts[0]] = parts[1] + } + } + + return config +} + +// 类型处理函数 +func joinStrings(separator string, strings ...string) string { + return strings.Join(strings, separator) +} + +func printValues(prefix string, values ...interface{}) { + fmt.Printf(" %s ", prefix) + for i, value := range values { + if i > 0 { + fmt.Printf(", ") + } + fmt.Printf("%v", value) + } + fmt.Printf("\n") +} + +type Person struct { + Name string + Age int +} + +func calculateAverageAge(people ...Person) float64 { + if len(people) == 0 { + return 0 + } + + totalAge := 0 + for _, person := range people { + totalAge += person.Age + } + + return float64(totalAge) / float64(len(people)) +} + +func applyOperations(a, b int, operations ...func(int, int) int) []int { + results := make([]int, len(operations)) + for i, op := range operations { + results[i] = op(a, b) + } + return results +} + +// 实际应用函数 +func logInfo(message string, keyValues ...interface{}) { + fmt.Printf(" [INFO] %s", message) + for i := 0; i < len(keyValues); i += 2 { + if i+1 < len(keyValues) { + fmt.Printf(" %v=%v", keyValues[i], keyValues[i+1]) + } + } + fmt.Printf("\n") +} + +func logError(message string, keyValues ...interface{}) { + fmt.Printf(" [ERROR] %s", message) + for i := 0; i < len(keyValues); i += 2 { + if i+1 < len(keyValues) { + fmt.Printf(" %v=%v", keyValues[i], keyValues[i+1]) + } + } + fmt.Printf("\n") +} + +func logDebug(message string, keyValues ...interface{}) { + fmt.Printf(" [DEBUG] %s", message) + for i := 0; i < len(keyValues); i += 2 { + if i+1 < len(keyValues) { + fmt.Printf(" %v=%v", keyValues[i], keyValues[i+1]) + } + } + fmt.Printf("\n") +} + +func buildSelectQuery(table string, columns ...string) string { + if len(columns) == 0 { + return fmt.Sprintf("SELECT * FROM %s", table) + } + return fmt.Sprintf("SELECT %s FROM %s", strings.Join(columns, ", "), table) +} + +// 模拟中间件和处理器 +func authMiddleware() { fmt.Printf(" - 认证中间件\n") } +func loggingMiddleware() { fmt.Printf(" - 日志中间件\n") } +func validateMiddleware() { fmt.Printf(" - 验证中间件\n") } +func getUsersHandler() { fmt.Printf(" - 获取用户处理器\n") } +func createUserHandler() { fmt.Printf(" - 创建用户处理器\n") } + +func registerRoute(method, path string, handlers ...func()) { + fmt.Printf(" 注册路由: %s %s\n", method, path) + for _, handler := range handlers { + handler() + } +} + +// 验证函数类型 +type ValidationFunc func(map[string]interface{}) []string + +func validateRequired(field string) ValidationFunc { + return func(data map[string]interface{}) []string { + if _, exists := data[field]; !exists { + return []string{fmt.Sprintf("字段 %s 是必需的", field)} + } + return nil + } +} + +func validateEmail(field string) ValidationFunc { + return func(data map[string]interface{}) []string { + if email, ok := data[field].(string); ok { + if !strings.Contains(email, "@") { + return []string{fmt.Sprintf("字段 %s 不是有效的邮箱", field)} + } + } + return nil + } +} + +func validateRange(field string, min, max int) ValidationFunc { + return func(data map[string]interface{}) []string { + if value, ok := data[field].(int); ok { + if value < min || value > max { + return []string{fmt.Sprintf("字段 %s 必须在 %d-%d 范围内", field, min, max)} + } + } + return nil + } +} + +func validateData(data map[string]interface{}, validators ...ValidationFunc) []string { + var allErrors []string + for _, validator := range validators { + if errors := validator(data); errors != nil { + allErrors = append(allErrors, errors...) + } + } + return allErrors +} + +// 配置合并 +type Config struct { + Port int + Debug bool + Timeout int + MaxConnections int +} + +func mergeConfigs(configs ...Config) Config { + result := Config{} + + for _, config := range configs { + if config.Port != 0 { + result.Port = config.Port + } + if config.Debug { + result.Debug = config.Debug + } + if config.Timeout != 0 { + result.Timeout = config.Timeout + } + if config.MaxConnections != 0 { + result.MaxConnections = config.MaxConnections + } + } + + return result +} + +// 高级用法函数 +func recursiveSum(numbers ...int) int { + if len(numbers) == 0 { + return 0 + } + if len(numbers) == 1 { + return numbers[0] + } + return numbers[0] + recursiveSum(numbers[1:]...) +} + +func filterInts(numbers []int, predicate func(int) bool) []int { + var result []int + for _, num := range numbers { + if predicate(num) { + result = append(result, num) + } + } + return result +} + +func reduceInts(numbers ...int) int { + return sum(numbers...) +} + +func isEven(n int) bool { return n%2 == 0 } +func isOdd(n int) bool { return n%2 == 1 } + +func createPipeline(functions ...func(int) int) func(int) int { + return func(input int) int { + result := input + for _, fn := range functions { + result = fn(result) + } + return result + } +} + +// 选项模式 +type Server struct { + Host string + Port int + Timeout int + Debug bool + MaxConnections int +} + +type ServerOption func(*Server) + +func withPort(port int) ServerOption { + return func(s *Server) { + s.Port = port + } +} + +func withTimeout(timeout int) ServerOption { + return func(s *Server) { + s.Timeout = timeout + } +} + +func withDebug(debug bool) ServerOption { + return func(s *Server) { + s.Debug = debug + } +} + +func withMaxConnections(max int) ServerOption { + return func(s *Server) { + s.MaxConnections = max + } +} + +func createServer(host string, options ...ServerOption) Server { + server := Server{ + Host: host, + Port: 80, + Timeout: 10, + Debug: false, + } + + for _, option := range options { + option(&server) + } + + return server +} + +// 限制和注意事项函数 +func inspectVariadicParam(numbers ...int) { + fmt.Printf(" 可变参数类型: %T\n", numbers) + fmt.Printf(" 可变参数长度: %d\n", len(numbers)) + fmt.Printf(" 可变参数容量: %d\n", cap(numbers)) + fmt.Printf(" 可变参数值: %v\n", numbers) +} + +func modifyVariadicParam(numbers ...int) { + if len(numbers) > 0 { + numbers[0] = 999 // 修改第一个元素 + } +} + +/* +运行这个程序: +go run 03-variadic-functions.go + +学习要点: +1. 可变参数使用 ...type 语法,必须是函数的最后一个参数 +2. 可变参数在函数内部是切片类型 +3. 传递切片给可变参数函数需要使用 ... 展开操作符 +4. 一个函数只能有一个可变参数 +5. 可变参数提供了灵活的函数调用方式 + +可变参数的语法: +- 定义: func name(params ...type) { ... } +- 调用: name(arg1, arg2, arg3) 或 name(slice...) +- 内部: params 是 []type 类型的切片 + +常见应用场景: +1. 数学运算函数(求和、求积等) +2. 字符串处理函数 +3. 日志记录函数 +4. 配置和选项处理 +5. 中间件和处理器链 +6. 数据验证 +7. SQL 查询构建 + +最佳实践: +1. 优先考虑切片参数,可变参数适用于调用便利性 +2. 使用选项模式处理复杂的可选参数 +3. 注意可变参数的性能影响 +4. 保持函数签名的简洁性 +5. 合理使用接口类型的可变参数 + +限制和注意事项: +1. 可变参数必须是最后一个参数 +2. 一个函数只能有一个可变参数 +3. 可变参数是切片,修改会影响原始数据 +4. 大量参数时考虑性能影响 +5. 类型必须相同(除非使用 interface{}) + +高级用法: +1. 函数式编程风格 +2. 选项模式 +3. 中间件模式 +4. 管道处理 +5. 递归处理 +6. 配置合并 + +性能考虑: +1. 切片展开有一定开销 +2. 大量参数时考虑直接传递切片 +3. 避免在热点代码中过度使用 +4. 考虑内存分配的影响 +*/ \ No newline at end of file diff --git a/golang-learning/03-functions/04-closures.go b/golang-learning/03-functions/04-closures.go new file mode 100644 index 0000000..02cb3bf --- /dev/null +++ b/golang-learning/03-functions/04-closures.go @@ -0,0 +1,1006 @@ +/* +04-closures.go - Go 语言闭包详解 + +学习目标: +1. 理解闭包的概念和原理 +2. 掌握闭包的创建和使用 +3. 学会闭包的实际应用场景 +4. 了解闭包的内存管理 +5. 掌握闭包的最佳实践 + +知识点: +- 闭包的定义和特性 +- 词法作用域和变量捕获 +- 闭包的生命周期 +- 闭包与匿名函数的关系 +- 闭包的实际应用模式 +- 闭包的性能考虑 +*/ + +package main + +import ( + "fmt" + "math/rand" + "strings" + "time" +) + +func main() { + fmt.Println("=== Go 语言闭包详解 ===\n") + + // 演示闭包的基本概念 + demonstrateBasicClosures() + + // 演示变量捕获 + demonstrateVariableCapture() + + // 演示闭包的状态保持 + demonstrateStatefulClosures() + + // 演示闭包作为返回值 + demonstrateClosureReturns() + + // 演示闭包的实际应用 + demonstratePracticalApplications() + + // 演示闭包的高级用法 + demonstrateAdvancedClosureUsage() + + // 演示闭包的注意事项 + demonstrateClosureCaveats() +} + +// demonstrateBasicClosures 演示闭包的基本概念 +func demonstrateBasicClosures() { + fmt.Println("1. 闭包的基本概念:") + + // 基本闭包示例 + fmt.Printf(" 基本闭包示例:\n") + + // 外部变量 + message := "Hello from closure" + + // 创建闭包 - 匿名函数访问外部变量 + closure := func() { + fmt.Printf(" 闭包访问外部变量: %s\n", message) + } + + // 调用闭包 + closure() + + // 修改外部变量 + message = "Modified message" + closure() // 闭包看到修改后的值 + + // 闭包修改外部变量 + fmt.Printf(" 闭包修改外部变量:\n") + counter := 0 + + increment := func() { + counter++ + fmt.Printf(" 计数器值: %d\n", counter) + } + + increment() + increment() + increment() + + fmt.Printf(" 外部变量 counter 的最终值: %d\n", counter) + + // 多个闭包共享变量 + fmt.Printf(" 多个闭包共享变量:\n") + sharedValue := 10 + + add := func(n int) { + sharedValue += n + fmt.Printf(" add(%d): sharedValue = %d\n", n, sharedValue) + } + + multiply := func(n int) { + sharedValue *= n + fmt.Printf(" multiply(%d): sharedValue = %d\n", n, sharedValue) + } + + add(5) // 10 + 5 = 15 + multiply(2) // 15 * 2 = 30 + add(10) // 30 + 10 = 40 + + fmt.Println() +} + +// demonstrateVariableCapture 演示变量捕获 +func demonstrateVariableCapture() { + fmt.Println("2. 变量捕获:") + + // 值捕获 vs 引用捕获 + fmt.Printf(" 值类型变量的捕获:\n") + + // 创建多个闭包,每个捕获不同的值 + var functions []func() + + for i := 0; i < 3; i++ { + // 错误的方式:所有闭包都会捕获同一个变量 i + functions = append(functions, func() { + fmt.Printf(" 错误方式 - i = %d\n", i) + }) + } + + fmt.Printf(" 错误的捕获方式(所有闭包都捕获同一个变量):\n") + for _, fn := range functions { + fn() // 都会打印 3,因为循环结束后 i = 3 + } + + // 正确的方式:为每个闭包创建独立的变量 + functions = nil + for i := 0; i < 3; i++ { + i := i // 创建新的变量,捕获当前值 + functions = append(functions, func() { + fmt.Printf(" 正确方式 - i = %d\n", i) + }) + } + + fmt.Printf(" 正确的捕获方式(每个闭包捕获独立的变量):\n") + for _, fn := range functions { + fn() + } + + // 引用类型的捕获 + fmt.Printf(" 引用类型变量的捕获:\n") + slice := []int{1, 2, 3} + + modifySlice := func() { + slice[0] = 999 + fmt.Printf(" 闭包修改切片: %v\n", slice) + } + + fmt.Printf(" 原始切片: %v\n", slice) + modifySlice() + fmt.Printf(" 外部切片: %v\n", slice) + + fmt.Println() +} + +// demonstrateStatefulClosures 演示闭包的状态保持 +func demonstrateStatefulClosures() { + fmt.Println("3. 闭包的状态保持:") + + // 计数器闭包 + fmt.Printf(" 计数器闭包:\n") + counter1 := createCounter() + counter2 := createCounter() + + fmt.Printf(" counter1: %d\n", counter1()) + fmt.Printf(" counter1: %d\n", counter1()) + fmt.Printf(" counter2: %d\n", counter2()) + fmt.Printf(" counter1: %d\n", counter1()) + fmt.Printf(" counter2: %d\n", counter2()) + + // 累加器闭包 + fmt.Printf(" 累加器闭包:\n") + adder := createAdder(10) // 初始值为 10 + + fmt.Printf(" adder(5): %d\n", adder(5)) // 10 + 5 = 15 + fmt.Printf(" adder(3): %d\n", adder(3)) // 15 + 3 = 18 + fmt.Printf(" adder(-8): %d\n", adder(-8)) // 18 - 8 = 10 + + // 银行账户闭包 + fmt.Printf(" 银行账户闭包:\n") + account := createBankAccount(1000.0) + + fmt.Printf(" 初始余额: %.2f\n", account.getBalance()) + fmt.Printf(" 存款 500: %.2f\n", account.deposit(500)) + fmt.Printf(" 取款 200: %.2f\n", account.withdraw(200)) + fmt.Printf(" 取款 2000: %.2f\n", account.withdraw(2000)) // 余额不足 + + // 历史记录闭包 + fmt.Printf(" 历史记录闭包:\n") + history := createHistory() + + history.add("用户登录") + history.add("查看订单") + history.add("添加商品到购物车") + history.add("结算订单") + + fmt.Printf(" 历史记录:\n") + for i, record := range history.getAll() { + fmt.Printf(" %d. %s\n", i+1, record) + } + + fmt.Printf(" 最近3条记录:\n") + for i, record := range history.getLast(3) { + fmt.Printf(" %d. %s\n", i+1, record) + } + + fmt.Println() +} + +// demonstrateClosureReturns 演示闭包作为返回值 +func demonstrateClosureReturns() { + fmt.Println("4. 闭包作为返回值:") + + // 数学运算闭包工厂 + fmt.Printf(" 数学运算闭包工厂:\n") + + add := createMathOperation("add") + multiply := createMathOperation("multiply") + power := createMathOperation("power") + + fmt.Printf(" add(10, 5) = %.2f\n", add(10, 5)) + fmt.Printf(" multiply(10, 5) = %.2f\n", multiply(10, 5)) + fmt.Printf(" power(2, 8) = %.2f\n", power(2, 8)) + + // 验证器闭包工厂 + fmt.Printf(" 验证器闭包工厂:\n") + + emailValidator := createValidator("email") + phoneValidator := createValidator("phone") + ageValidator := createValidator("age") + + testData := []struct { + validator func(string) bool + name string + values []string + }{ + {emailValidator, "邮箱", []string{"user@example.com", "invalid-email", "test@domain.org"}}, + {phoneValidator, "电话", []string{"138-1234-5678", "123", "186-9999-8888"}}, + {ageValidator, "年龄", []string{"25", "abc", "150", "30"}}, + } + + for _, test := range testData { + fmt.Printf(" %s验证:\n", test.name) + for _, value := range test.values { + isValid := test.validator(value) + fmt.Printf(" \"%s\": %t\n", value, isValid) + } + } + + // 配置闭包工厂 + fmt.Printf(" 配置闭包工厂:\n") + + devConfig := createConfigGetter("development") + prodConfig := createConfigGetter("production") + + fmt.Printf(" 开发环境数据库: %s\n", devConfig("database")) + fmt.Printf(" 开发环境端口: %s\n", devConfig("port")) + fmt.Printf(" 生产环境数据库: %s\n", prodConfig("database")) + fmt.Printf(" 生产环境端口: %s\n", prodConfig("port")) + + fmt.Println() +} + +// demonstratePracticalApplications 演示闭包的实际应用 +func demonstratePracticalApplications() { + fmt.Println("5. 闭包的实际应用:") + + // 应用1: 事件处理器 + fmt.Printf(" 应用1 - 事件处理器:\n") + + button := createButton("提交按钮") + + // 添加点击事件处理器 + button.onClick(func() { + fmt.Printf(" 按钮被点击了!\n") + }) + + // 添加多个事件处理器 + button.onClick(func() { + fmt.Printf(" 记录点击日志\n") + }) + + button.onClick(func() { + fmt.Printf(" 发送统计数据\n") + }) + + // 触发点击事件 + button.click() + + // 应用2: 缓存系统 + fmt.Printf(" 应用2 - 缓存系统:\n") + + cache := createCache() + + // 设置缓存 + cache.set("user:123", "Alice") + cache.set("user:456", "Bob") + + // 获取缓存 + if value, found := cache.get("user:123"); found { + fmt.Printf(" 缓存命中: user:123 = %s\n", value) + } + + if value, found := cache.get("user:789"); found { + fmt.Printf(" 缓存命中: user:789 = %s\n", value) + } else { + fmt.Printf(" 缓存未命中: user:789\n") + } + + // 显示缓存统计 + stats := cache.getStats() + fmt.Printf(" 缓存统计: 命中 %d 次,未命中 %d 次\n", stats.hits, stats.misses) + + // 应用3: 中间件模式 + fmt.Printf(" 应用3 - 中间件模式:\n") + + // 创建处理器 + handler := func(request string) string { + return fmt.Sprintf("处理请求: %s", request) + } + + // 应用中间件 + withLogging := loggingMiddleware(handler) + withAuth := authMiddleware(withLogging) + withRateLimit := rateLimitMiddleware(withAuth) + + // 处理请求 + result := withRateLimit("GET /api/users") + fmt.Printf(" 最终结果: %s\n", result) + + // 应用4: 函数式编程 + fmt.Printf(" 应用4 - 函数式编程:\n") + + numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + + // 使用闭包进行函数式操作 + evenNumbers := filter(numbers, func(n int) bool { return n%2 == 0 }) + fmt.Printf(" 偶数: %v\n", evenNumbers) + + squares := mapInts(numbers, func(n int) int { return n * n }) + fmt.Printf(" 平方: %v\n", squares) + + sum := reduce(numbers, 0, func(acc, n int) int { return acc + n }) + fmt.Printf(" 求和: %d\n", sum) + + // 应用5: 延迟执行 + fmt.Printf(" 应用5 - 延迟执行:\n") + + // 创建延迟任务 + task1 := createDelayedTask("任务1", func() { + fmt.Printf(" 执行任务1: 发送邮件\n") + }) + + task2 := createDelayedTask("任务2", func() { + fmt.Printf(" 执行任务2: 清理缓存\n") + }) + + // 延迟执行 + fmt.Printf(" 创建延迟任务...\n") + time.Sleep(100 * time.Millisecond) + + task1.execute() + task2.execute() + + fmt.Println() +} + +// demonstrateAdvancedClosureUsage 演示闭包的高级用法 +func demonstrateAdvancedClosureUsage() { + fmt.Println("6. 闭包的高级用法:") + + // 高级用法1: 柯里化 + fmt.Printf(" 高级用法1 - 柯里化:\n") + + // 创建柯里化的加法函数 + curriedAdd := curry(func(a, b, c int) int { + return a + b + c + }) + + // 部分应用 + add5 := curriedAdd(5) + add5And3 := add5(3) + + result := add5And3(2) // 5 + 3 + 2 = 10 + fmt.Printf(" 柯里化结果: 5 + 3 + 2 = %d\n", result) + + // 高级用法2: 记忆化 + fmt.Printf(" 高级用法2 - 记忆化:\n") + + // 创建记忆化的斐波那契函数 + memoFib := memoize(fibonacci) + + fmt.Printf(" 计算斐波那契数列:\n") + for i := 0; i <= 10; i++ { + result := memoFib(i) + fmt.Printf(" fib(%d) = %d\n", i, result) + } + + // 高级用法3: 装饰器模式 + fmt.Printf(" 高级用法3 - 装饰器模式:\n") + + // 原始函数 + slowFunction := func(n int) int { + time.Sleep(10 * time.Millisecond) // 模拟慢操作 + return n * n + } + + // 应用装饰器 + timedFunction := withTiming(slowFunction) + cachedFunction := withCaching(timedFunction) + + fmt.Printf(" 第一次调用:\n") + result1 := cachedFunction(5) + fmt.Printf(" 结果: %d\n", result1) + + fmt.Printf(" 第二次调用(应该使用缓存):\n") + result2 := cachedFunction(5) + fmt.Printf(" 结果: %d\n", result2) + + // 高级用法4: 状态机 + fmt.Printf(" 高级用法4 - 状态机:\n") + + fsm := createStateMachine() + + fmt.Printf(" 当前状态: %s\n", fsm.getState()) + fsm.start() + fmt.Printf(" 当前状态: %s\n", fsm.getState()) + fsm.pause() + fmt.Printf(" 当前状态: %s\n", fsm.getState()) + fsm.resume() + fmt.Printf(" 当前状态: %s\n", fsm.getState()) + fsm.stop() + fmt.Printf(" 当前状态: %s\n", fsm.getState()) + + // 高级用法5: 观察者模式 + fmt.Printf(" 高级用法5 - 观察者模式:\n") + + subject := createSubject() + + // 添加观察者 + subject.subscribe(func(data interface{}) { + fmt.Printf(" 观察者1收到数据: %v\n", data) + }) + + subject.subscribe(func(data interface{}) { + fmt.Printf(" 观察者2收到数据: %v\n", data) + }) + + // 通知观察者 + subject.notify("Hello, Observers!") + subject.notify(42) + + fmt.Println() +} + +// demonstrateClosureCaveats 演示闭包的注意事项 +func demonstrateClosureCaveats() { + fmt.Println("7. 闭包的注意事项:") + + // 注意事项1: 循环变量捕获 + fmt.Printf(" 注意事项1 - 循环变量捕获:\n") + fmt.Printf(" 这是一个常见的陷阱,前面已经演示过\n") + + // 注意事项2: 内存泄漏 + fmt.Printf(" 注意事项2 - 内存泄漏风险:\n") + fmt.Printf(" 闭包会保持对外部变量的引用,可能导致内存泄漏\n") + + // 创建一个可能导致内存泄漏的示例 + largeData := make([]int, 1000000) // 大数组 + for i := range largeData { + largeData[i] = i + } + + // 闭包只使用数组的第一个元素,但会保持整个数组的引用 + getClosure := func() func() int { + return func() int { + return largeData[0] // 只使用第一个元素 + } + } + + closure := getClosure() + fmt.Printf(" 闭包结果: %d\n", closure()) + fmt.Printf(" 注意: 闭包保持了整个大数组的引用\n") + + // 更好的做法:只捕获需要的数据 + getBetterClosure := func() func() int { + firstElement := largeData[0] // 只捕获需要的值 + return func() int { + return firstElement + } + } + + betterClosure := getBetterClosure() + fmt.Printf(" 改进的闭包结果: %d\n", betterClosure()) + fmt.Printf(" 改进: 只捕获需要的值,不保持大数组引用\n") + + // 注意事项3: 性能考虑 + fmt.Printf(" 注意事项3 - 性能考虑:\n") + fmt.Printf(" 闭包的创建和调用有一定的性能开销\n") + + // 测量闭包 vs 普通函数的性能 + normalFunc := func(x int) int { return x * 2 } + + multiplier := 2 + closureFunc := func(x int) int { return x * multiplier } + + // 简单的性能比较(实际测试需要更严格的基准测试) + start := time.Now() + for i := 0; i < 1000000; i++ { + normalFunc(i) + } + normalTime := time.Since(start) + + start = time.Now() + for i := 0; i < 1000000; i++ { + closureFunc(i) + } + closureTime := time.Since(start) + + fmt.Printf(" 普通函数耗时: %v\n", normalTime) + fmt.Printf(" 闭包函数耗时: %v\n", closureTime) + + // 最佳实践 + fmt.Printf(" 最佳实践:\n") + fmt.Printf(" 1. 避免在循环中直接使用循环变量创建闭包\n") + fmt.Printf(" 2. 只捕获必要的变量,避免捕获大对象\n") + fmt.Printf(" 3. 注意闭包的生命周期,避免内存泄漏\n") + fmt.Printf(" 4. 在性能敏感的代码中谨慎使用闭包\n") + fmt.Printf(" 5. 使用闭包实现优雅的设计模式\n") + + fmt.Println() +} + +// ========== 函数定义 ========== + +// 基本闭包函数 +func createCounter() func() int { + count := 0 + return func() int { + count++ + return count + } +} + +func createAdder(initial int) func(int) int { + sum := initial + return func(n int) int { + sum += n + return sum + } +} + +// 银行账户闭包 +type BankAccount struct { + getBalance func() float64 + deposit func(float64) float64 + withdraw func(float64) float64 +} + +func createBankAccount(initialBalance float64) BankAccount { + balance := initialBalance + + return BankAccount{ + getBalance: func() float64 { + return balance + }, + deposit: func(amount float64) float64 { + if amount > 0 { + balance += amount + } + return balance + }, + withdraw: func(amount float64) float64 { + if amount > 0 && amount <= balance { + balance -= amount + } + return balance + }, + } +} + +// 历史记录闭包 +type History struct { + add func(string) + getAll func() []string + getLast func(int) []string +} + +func createHistory() History { + var records []string + + return History{ + add: func(record string) { + records = append(records, record) + }, + getAll: func() []string { + result := make([]string, len(records)) + copy(result, records) + return result + }, + getLast: func(n int) []string { + if n >= len(records) { + result := make([]string, len(records)) + copy(result, records) + return result + } + result := make([]string, n) + copy(result, records[len(records)-n:]) + return result + }, + } +} + +// 数学运算闭包工厂 +func createMathOperation(operation string) func(float64, float64) float64 { + switch operation { + case "add": + return func(a, b float64) float64 { return a + b } + case "subtract": + return func(a, b float64) float64 { return a - b } + case "multiply": + return func(a, b float64) float64 { return a * b } + case "divide": + return func(a, b float64) float64 { + if b != 0 { + return a / b + } + return 0 + } + case "power": + return func(a, b float64) float64 { + result := 1.0 + for i := 0; i < int(b); i++ { + result *= a + } + return result + } + default: + return func(a, b float64) float64 { return 0 } + } +} + +// 验证器闭包工厂 +func createValidator(validationType string) func(string) bool { + switch validationType { + case "email": + return func(email string) bool { + return len(email) > 0 && + strings.Contains(email, "@") && + strings.Contains(email, ".") + } + case "phone": + return func(phone string) bool { + return len(phone) >= 10 && strings.Contains(phone, "-") + } + case "age": + return func(ageStr string) bool { + // 简单验证:只检查是否为数字 + for _, char := range ageStr { + if char < '0' || char > '9' { + return false + } + } + return len(ageStr) > 0 + } + default: + return func(string) bool { return false } + } +} + +// 配置闭包工厂 +func createConfigGetter(environment string) func(string) string { + configs := map[string]map[string]string{ + "development": { + "database": "localhost:5432", + "port": "8080", + "debug": "true", + }, + "production": { + "database": "prod-db:5432", + "port": "80", + "debug": "false", + }, + } + + envConfig := configs[environment] + + return func(key string) string { + if value, exists := envConfig[key]; exists { + return value + } + return "" + } +} + +// 事件处理器 +type Button struct { + name string + handlers []func() +} + +func createButton(name string) *Button { + return &Button{name: name} +} + +func (b *Button) onClick(handler func()) { + b.handlers = append(b.handlers, handler) +} + +func (b *Button) click() { + fmt.Printf(" 点击按钮: %s\n", b.name) + for _, handler := range b.handlers { + handler() + } +} + +// 缓存系统 +type Cache struct { + set func(string, string) + get func(string) (string, bool) + getStats func() struct{ hits, misses int } +} + +func createCache() Cache { + data := make(map[string]string) + hits := 0 + misses := 0 + + return Cache{ + set: func(key, value string) { + data[key] = value + }, + get: func(key string) (string, bool) { + if value, exists := data[key]; exists { + hits++ + return value, true + } + misses++ + return "", false + }, + getStats: func() struct{ hits, misses int } { + return struct{ hits, misses int }{hits, misses} + }, + } +} + +// 中间件模式 +func loggingMiddleware(next func(string) string) func(string) string { + return func(request string) string { + fmt.Printf(" [LOG] 处理请求: %s\n", request) + result := next(request) + fmt.Printf(" [LOG] 请求完成: %s\n", request) + return result + } +} + +func authMiddleware(next func(string) string) func(string) string { + return func(request string) string { + fmt.Printf(" [AUTH] 验证请求: %s\n", request) + // 模拟认证 + if strings.Contains(request, "GET") { + return next(request) + } + return "认证失败" + } +} + +func rateLimitMiddleware(next func(string) string) func(string) string { + requestCount := 0 + return func(request string) string { + requestCount++ + fmt.Printf(" [RATE] 请求计数: %d\n", requestCount) + if requestCount > 10 { + return "请求过于频繁" + } + return next(request) + } +} + +// 函数式编程辅助函数 +func filter(slice []int, predicate func(int) bool) []int { + var result []int + for _, item := range slice { + if predicate(item) { + result = append(result, item) + } + } + return result +} + +func mapInts(slice []int, mapper func(int) int) []int { + result := make([]int, len(slice)) + for i, item := range slice { + result[i] = mapper(item) + } + return result +} + +func reduce(slice []int, initial int, reducer func(int, int) int) int { + result := initial + for _, item := range slice { + result = reducer(result, item) + } + return result +} + +// 延迟执行 +type DelayedTask struct { + name string + task func() + execute func() +} + +func createDelayedTask(name string, task func()) DelayedTask { + return DelayedTask{ + name: name, + task: task, + execute: func() { + fmt.Printf(" 准备执行延迟任务: %s\n", name) + task() + }, + } +} + +// 柯里化 +func curry(fn func(int, int, int) int) func(int) func(int) func(int) int { + return func(a int) func(int) func(int) int { + return func(b int) func(int) int { + return func(c int) int { + return fn(a, b, c) + } + } + } +} + +// 记忆化 +func memoize(fn func(int) int) func(int) int { + cache := make(map[int]int) + return func(n int) int { + if result, exists := cache[n]; exists { + return result + } + result := fn(n) + cache[n] = result + return result + } +} + +func fibonacci(n int) int { + if n <= 1 { + return n + } + return fibonacci(n-1) + fibonacci(n-2) +} + +// 装饰器模式 +func withTiming(fn func(int) int) func(int) int { + return func(n int) int { + start := time.Now() + result := fn(n) + duration := time.Since(start) + fmt.Printf(" 函数执行耗时: %v\n", duration) + return result + } +} + +func withCaching(fn func(int) int) func(int) int { + cache := make(map[int]int) + return func(n int) int { + if result, exists := cache[n]; exists { + fmt.Printf(" 使用缓存结果\n") + return result + } + fmt.Printf(" 计算新结果\n") + result := fn(n) + cache[n] = result + return result + } +} + +// 状态机 +type StateMachine struct { + getState func() string + start func() + pause func() + resume func() + stop func() +} + +func createStateMachine() StateMachine { + state := "idle" + + return StateMachine{ + getState: func() string { + return state + }, + start: func() { + if state == "idle" { + state = "running" + } + }, + pause: func() { + if state == "running" { + state = "paused" + } + }, + resume: func() { + if state == "paused" { + state = "running" + } + }, + stop: func() { + if state == "running" || state == "paused" { + state = "idle" + } + }, + } +} + +// 观察者模式 +type Subject struct { + subscribe func(func(interface{})) + notify func(interface{}) +} + +func createSubject() Subject { + var observers []func(interface{}) + + return Subject{ + subscribe: func(observer func(interface{})) { + observers = append(observers, observer) + }, + notify: func(data interface{}) { + for _, observer := range observers { + observer(data) + } + }, + } +} + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +/* +运行这个程序: +go run 04-closures.go + +学习要点: +1. 闭包是函数和其词法环境的组合 +2. 闭包可以访问和修改外部作用域的变量 +3. 闭包可以保持状态,实现数据封装 +4. 闭包常用于回调函数、事件处理、函数式编程 +5. 需要注意循环变量捕获和内存泄漏问题 + +闭包的特性: +1. 词法作用域:闭包可以访问定义时的作用域 +2. 变量捕获:闭包会捕获外部变量的引用 +3. 状态保持:闭包可以在多次调用间保持状态 +4. 延迟执行:闭包可以延迟执行代码 + +常见应用场景: +1. 事件处理和回调函数 +2. 函数式编程(map、filter、reduce) +3. 中间件和装饰器模式 +4. 状态管理和数据封装 +5. 配置和选项处理 +6. 缓存和记忆化 +7. 延迟执行和任务调度 + +设计模式: +1. 工厂模式:返回配置好的闭包 +2. 装饰器模式:包装函数添加功能 +3. 观察者模式:事件处理和通知 +4. 状态机模式:状态管理 +5. 策略模式:动态选择算法 + +最佳实践: +1. 避免在循环中直接捕获循环变量 +2. 只捕获必要的变量,避免内存泄漏 +3. 合理使用闭包实现优雅的API设计 +4. 注意闭包的性能开销 +5. 使用闭包实现函数式编程风格 + +注意事项: +1. 循环变量捕获陷阱 +2. 内存泄漏风险 +3. 性能开销 +4. 调试困难 +5. 代码可读性 + +高级用法: +1. 柯里化和部分应用 +2. 记忆化优化 +3. 函数组合和管道 +4. 异步编程模式 +5. 依赖注入 +*/ \ No newline at end of file diff --git a/golang-learning/03-functions/05-methods.go b/golang-learning/03-functions/05-methods.go new file mode 100644 index 0000000..0cb1a5f --- /dev/null +++ b/golang-learning/03-functions/05-methods.go @@ -0,0 +1,869 @@ +/* +05-methods.go - Go 语言方法详解 + +学习目标: +1. 理解方法与函数的区别 +2. 掌握方法的定义和调用 +3. 学会值接收者和指针接收者的使用 +4. 了解方法集的概念 +5. 掌握方法的实际应用 + +知识点: +- 方法定义语法 +- 值接收者 vs 指针接收者 +- 方法集和接口实现 +- 方法的继承和组合 +- 方法的实际应用场景 +*/ + +package main + +import ( + "fmt" +) + +func main() { + fmt.Println("=== Go 语言方法详解 ===\n") + + // 演示基本方法定义和调用 + demonstrateBasicMethods() + + // 演示值接收者和指针接收者 + demonstrateReceiverTypes() + + // 演示方法集和接口实现 + demonstrateMethodSets() + + // 演示方法的继承和组合 + demonstrateMethodComposition() + + // 演示方法的实际应用 + demonstratePracticalApplications() + + // 演示方法的高级用法 + demonstrateAdvancedMethodUsage() +} + +// demonstrateBasicMethods 演示基本方法定义和调用 +func demonstrateBasicMethods() { + fmt.Println("1. 基本方法定义和调用:") + + // 创建结构体实例 + fmt.Printf(" 创建和使用基本方法:\n") + + rect := Rectangle{Width: 10, Height: 5} + fmt.Printf(" 矩形: %+v\n", rect) + fmt.Printf(" 面积: %.2f\n", rect.Area()) + fmt.Printf(" 周长: %.2f\n", rect.Perimeter()) + + // 方法链调用 + fmt.Printf(" 方法链调用:\n") + rect.SetWidth(8).SetHeight(6) + fmt.Printf(" 修改后的矩形: %+v\n", rect) + fmt.Printf(" 新面积: %.2f\n", rect.Area()) + + // 不同类型的方法 + fmt.Printf(" 不同类型的方法:\n") + + circle := Circle{Radius: 3} + fmt.Printf(" 圆形: %+v\n", circle) + fmt.Printf(" 面积: %.2f\n", circle.Area()) + fmt.Printf(" 周长: %.2f\n", circle.Circumference()) + + // 基本类型的方法 + fmt.Printf(" 基本类型的方法:\n") + + var temp Temperature = 25.5 + fmt.Printf(" 温度: %.1f°C\n", temp) + fmt.Printf(" 华氏度: %.1f°F\n", temp.ToFahrenheit()) + fmt.Printf(" 开尔文: %.1f K\n", temp.ToKelvin()) + + fmt.Println() +}// demonstr +ateReceiverTypes 演示值接收者和指针接收者 +func demonstrateReceiverTypes() { + fmt.Println("2. 值接收者和指针接收者:") + + // 值接收者示例 + fmt.Printf(" 值接收者示例:\n") + + counter1 := Counter{Value: 0} + fmt.Printf(" 初始计数器: %+v\n", counter1) + + // 值接收者方法不会修改原始值 + counter1.IncrementByValue() + fmt.Printf(" 值接收者增加后: %+v\n", counter1) // 值不变 + + // 指针接收者示例 + fmt.Printf(" 指针接收者示例:\n") + + counter2 := Counter{Value: 0} + fmt.Printf(" 初始计数器: %+v\n", counter2) + + // 指针接收者方法会修改原始值 + counter2.IncrementByPointer() + fmt.Printf(" 指针接收者增加后: %+v\n", counter2) // 值改变 + + // 方法调用的自动转换 + fmt.Printf(" 方法调用的自动转换:\n") + + counter3 := Counter{Value: 10} + counterPtr := &counter3 + + // 值类型可以调用指针接收者方法(自动取地址) + counter3.IncrementByPointer() + fmt.Printf(" 值类型调用指针方法: %+v\n", counter3) + + // 指针类型可以调用值接收者方法(自动解引用) + result := counterPtr.GetValueCopy() + fmt.Printf(" 指针类型调用值方法: %d\n", result) + + // 大结构体的性能考虑 + fmt.Printf(" 大结构体的性能考虑:\n") + + largeStruct := LargeStruct{} + for i := 0; i < 1000; i++ { + largeStruct.Data[i] = i + } + + // 值接收者会拷贝整个结构体 + start := time.Now() + largeStruct.ProcessByValue() + valueTime := time.Since(start) + + // 指针接收者只传递指针 + start = time.Now() + largeStruct.ProcessByPointer() + pointerTime := time.Since(start) + + fmt.Printf(" 值接收者耗时: %v\n", valueTime) + fmt.Printf(" 指针接收者耗时: %v\n", pointerTime) + + fmt.Println() +} + +// demonstrateMethodSets 演示方法集和接口实现 +func demonstrateMethodSets() { + fmt.Println("3. 方法集和接口实现:") + + // 接口实现 + fmt.Printf(" 接口实现:\n") + + var shapes []Shape + shapes = append(shapes, Rectangle{Width: 4, Height: 3}) + shapes = append(shapes, Circle{Radius: 2}) + shapes = append(shapes, Triangle{Base: 6, Height: 4}) + + totalArea := 0.0 + for i, shape := range shapes { + area := shape.Area() + fmt.Printf(" 形状 %d 面积: %.2f\n", i+1, area) + totalArea += area + } + fmt.Printf(" 总面积: %.2f\n", totalArea) + + // 方法集的规则 + fmt.Printf(" 方法集的规则:\n") + + // 值类型的方法集 + var drawable1 Drawable = Rectangle{Width: 5, Height: 3} + drawable1.Draw() + + // 指针类型的方法集 + rect := Rectangle{Width: 5, Height: 3} + var drawable2 Drawable = &rect + drawable2.Draw() + + // 可修改接口 + fmt.Printf(" 可修改接口:\n") + + var modifiable Modifiable = &rect + fmt.Printf(" 修改前: %+v\n", rect) + modifiable.Modify() + fmt.Printf(" 修改后: %+v\n", rect) + + // 注意:值类型不能实现需要指针接收者的接口 + // var modifiable2 Modifiable = rect // 编译错误 + + fmt.Println() +} + +// demonstrateMethodComposition 演示方法的继承和组合 +func demonstrateMethodComposition() { + fmt.Println("4. 方法的继承和组合:") + + // 结构体嵌入 + fmt.Printf(" 结构体嵌入:\n") + + person := Person{ + Name: "Alice", + Age: 30, + } + + employee := Employee{ + Person: person, + JobTitle: "软件工程师", + Salary: 80000, + } + + // 可以直接调用嵌入类型的方法 + fmt.Printf(" 员工信息: %s\n", employee.GetInfo()) + fmt.Printf(" 员工详情: %s\n", employee.GetDetails()) + + // 匿名嵌入 + fmt.Printf(" 匿名嵌入:\n") + + manager := Manager{ + Person: Person{ + Name: "Bob", + Age: 35, + }, + Department: "技术部", + TeamSize: 10, + } + + // 直接访问嵌入类型的方法和字段 + fmt.Printf(" 经理姓名: %s\n", manager.Name) // 直接访问嵌入字段 + fmt.Printf(" 经理信息: %s\n", manager.GetInfo()) // 直接调用嵌入方法 + fmt.Printf(" 管理信息: %s\n", manager.Manage()) + + // 方法重写 + fmt.Printf(" 方法重写:\n") + + student := Student{ + Person: Person{ + Name: "Charlie", + Age: 20, + }, + School: "清华大学", + Grade: "大三", + } + + // Student 重写了 GetInfo 方法 + fmt.Printf(" 学生信息: %s\n", student.GetInfo()) + + // 仍然可以访问原始方法 + fmt.Printf(" 基础信息: %s\n", student.Person.GetInfo()) + + fmt.Println() +}// dem +onstratePracticalApplications 演示方法的实际应用 +func demonstratePracticalApplications() { + fmt.Println("5. 方法的实际应用:") + + // 应用1: 银行账户管理 + fmt.Printf(" 应用1 - 银行账户管理:\n") + + account := BankAccount{ + AccountNumber: "123456789", + Balance: 1000.0, + Owner: "Alice", + } + + fmt.Printf(" 初始账户: %s\n", account.GetInfo()) + + account.Deposit(500.0) + fmt.Printf(" 存款后: %s\n", account.GetInfo()) + + success := account.Withdraw(200.0) + fmt.Printf(" 取款成功: %t, 余额: %.2f\n", success, account.Balance) + + success = account.Withdraw(2000.0) + fmt.Printf(" 取款成功: %t, 余额: %.2f\n", success, account.Balance) + + // 应用2: 购物车系统 + fmt.Printf(" 应用2 - 购物车系统:\n") + + cart := ShoppingCart{} + + cart.AddItem("笔记本电脑", 5999.99, 1) + cart.AddItem("鼠标", 99.99, 2) + cart.AddItem("键盘", 299.99, 1) + + fmt.Printf(" 购物车内容:\n") + cart.DisplayItems() + + fmt.Printf(" 总价: %.2f\n", cart.GetTotal()) + + cart.RemoveItem("鼠标") + fmt.Printf(" 移除鼠标后总价: %.2f\n", cart.GetTotal()) + + // 应用3: 日志记录器 + fmt.Printf(" 应用3 - 日志记录器:\n") + + logger := Logger{Level: "INFO"} + + logger.Info("应用程序启动") + logger.Warning("配置文件使用默认值") + logger.Error("数据库连接失败") + logger.Debug("调试信息") // 不会显示,因为级别是 INFO + + logger.SetLevel("DEBUG") + logger.Debug("现在可以看到调试信息了") + + // 应用4: 配置管理器 + fmt.Printf(" 应用4 - 配置管理器:\n") + + config := Config{ + settings: make(map[string]string), + } + + config.Set("database.host", "localhost") + config.Set("database.port", "5432") + config.Set("app.debug", "true") + + fmt.Printf(" 数据库主机: %s\n", config.Get("database.host")) + fmt.Printf(" 应用调试: %s\n", config.Get("app.debug")) + fmt.Printf(" 不存在的配置: %s\n", config.Get("nonexistent")) + + fmt.Printf(" 所有配置:\n") + config.DisplayAll() + + fmt.Println() +} + +// demonstrateAdvancedMethodUsage 演示方法的高级用法 +func demonstrateAdvancedMethodUsage() { + fmt.Println("6. 方法的高级用法:") + + // 高级用法1: 方法表达式 + fmt.Printf(" 高级用法1 - 方法表达式:\n") + + rect := Rectangle{Width: 4, Height: 3} + + // 方法表达式:将方法转换为函数 + areaFunc := Rectangle.Area + perimeterFunc := Rectangle.Perimeter + + fmt.Printf(" 使用方法表达式计算面积: %.2f\n", areaFunc(rect)) + fmt.Printf(" 使用方法表达式计算周长: %.2f\n", perimeterFunc(rect)) + + // 高级用法2: 方法值 + fmt.Printf(" 高级用法2 - 方法值:\n") + + // 方法值:绑定到特定实例的方法 + rectAreaMethod := rect.Area + rectPerimeterMethod := rect.Perimeter + + fmt.Printf(" 使用方法值计算面积: %.2f\n", rectAreaMethod()) + fmt.Printf(" 使用方法值计算周长: %.2f\n", rectPerimeterMethod()) + + // 高级用法3: 接口组合 + fmt.Printf(" 高级用法3 - 接口组合:\n") + + var readWriter ReadWriter = &File{Name: "test.txt"} + + data := []byte("Hello, World!") + readWriter.Write(data) + + buffer := make([]byte, 20) + n := readWriter.Read(buffer) + fmt.Printf(" 读取到 %d 字节: %s\n", n, string(buffer[:n])) + + // 高级用法4: 类型断言和方法调用 + fmt.Printf(" 高级用法4 - 类型断言和方法调用:\n") + + var shape Shape = Circle{Radius: 5} + + // 类型断言获取具体类型 + if circle, ok := shape.(Circle); ok { + fmt.Printf(" 圆的半径: %.2f\n", circle.Radius) + fmt.Printf(" 圆的周长: %.2f\n", circle.Circumference()) + } + + // 高级用法5: 方法集的动态调用 + fmt.Printf(" 高级用法5 - 方法集的动态调用:\n") + + calculator := Calculator{} + + operations := []struct { + name string + method func(float64, float64) float64 + }{ + {"加法", calculator.Add}, + {"减法", calculator.Subtract}, + {"乘法", calculator.Multiply}, + {"除法", calculator.Divide}, + } + + a, b := 10.0, 3.0 + for _, op := range operations { + result := op.method(a, b) + fmt.Printf(" %.1f %s %.1f = %.2f\n", a, op.name, b, result) + } + + // 高级用法6: 链式方法调用 + fmt.Printf(" 高级用法6 - 链式方法调用:\n") + + builder := NewStringBuilder() + result := builder. + Append("Hello"). + Append(" "). + Append("World"). + Append("!"). + ToUpper(). + Build() + + fmt.Printf(" 构建结果: %s\n", result) + + fmt.Println() +}// = +========= 类型和方法定义 ========== + +// 基本结构体和方法 +type Rectangle struct { + Width float64 + Height float64 +} + +func (r Rectangle) Area() float64 { + return r.Width * r.Height +} + +func (r Rectangle) Perimeter() float64 { + return 2 * (r.Width + r.Height) +} + +// 指针接收者方法,支持方法链 +func (r *Rectangle) SetWidth(width float64) *Rectangle { + r.Width = width + return r +} + +func (r *Rectangle) SetHeight(height float64) *Rectangle { + r.Height = height + return r +} + +func (r Rectangle) Draw() { + fmt.Printf(" 绘制矩形: %.1f x %.1f\n", r.Width, r.Height) +} + +func (r *Rectangle) Modify() { + r.Width *= 1.1 + r.Height *= 1.1 + fmt.Printf(" 矩形已放大 10%%\n") +} + +// 圆形结构体和方法 +type Circle struct { + Radius float64 +} + +func (c Circle) Area() float64 { + return math.Pi * c.Radius * c.Radius +} + +func (c Circle) Circumference() float64 { + return 2 * math.Pi * c.Radius +} + +func (c Circle) Draw() { + fmt.Printf(" 绘制圆形: 半径 %.1f\n", c.Radius) +} + +// 三角形结构体和方法 +type Triangle struct { + Base float64 + Height float64 +} + +func (t Triangle) Area() float64 { + return 0.5 * t.Base * t.Height +} + +func (t Triangle) Draw() { + fmt.Printf(" 绘制三角形: 底边 %.1f, 高 %.1f\n", t.Base, t.Height) +} + +// 基本类型的方法 +type Temperature float64 + +func (t Temperature) ToFahrenheit() float64 { + return float64(t)*9/5 + 32 +} + +func (t Temperature) ToKelvin() float64 { + return float64(t) + 273.15 +} + +// 值接收者 vs 指针接收者示例 +type Counter struct { + Value int +} + +// 值接收者:不会修改原始值 +func (c Counter) IncrementByValue() { + c.Value++ + fmt.Printf(" 值接收者内部: %d\n", c.Value) +} + +// 指针接收者:会修改原始值 +func (c *Counter) IncrementByPointer() { + c.Value++ + fmt.Printf(" 指针接收者内部: %d\n", c.Value) +} + +func (c Counter) GetValueCopy() int { + return c.Value +} + +// 大结构体性能测试 +type LargeStruct struct { + Data [1000]int +} + +func (ls LargeStruct) ProcessByValue() { + // 值接收者会拷贝整个结构体 + sum := 0 + for _, v := range ls.Data { + sum += v + } +} + +func (ls *LargeStruct) ProcessByPointer() { + // 指针接收者只传递指针 + sum := 0 + for _, v := range ls.Data { + sum += v + } +} + +// 接口定义 +type Shape interface { + Area() float64 +} + +type Drawable interface { + Draw() +} + +type Modifiable interface { + Modify() +} + +// 组合接口 +type ReadWriter interface { + Reader + Writer +} + +type Reader interface { + Read([]byte) int +} + +type Writer interface { + Write([]byte) int +} + +// 文件类型实现 ReadWriter 接口 +type File struct { + Name string + data []byte +} + +func (f *File) Read(buffer []byte) int { + n := copy(buffer, f.data) + return n +} + +func (f *File) Write(data []byte) int { + f.data = append(f.data, data...) + return len(data) +} + +// 结构体嵌入示例 +type Person struct { + Name string + Age int +} + +func (p Person) GetInfo() string { + return fmt.Sprintf("%s (%d岁)", p.Name, p.Age) +} + +type Employee struct { + Person // 具名嵌入 + JobTitle string + Salary float64 +} + +func (e Employee) GetDetails() string { + return fmt.Sprintf("%s - %s, 薪资: %.0f", e.GetInfo(), e.JobTitle, e.Salary) +} + +// 匿名嵌入 +type Manager struct { + Person // 匿名嵌入 + Department string + TeamSize int +} + +func (m Manager) Manage() string { + return fmt.Sprintf("管理 %s,团队规模: %d人", m.Department, m.TeamSize) +} + +// 方法重写示例 +type Student struct { + Person + School string + Grade string +} + +// 重写 Person 的 GetInfo 方法 +func (s Student) GetInfo() string { + return fmt.Sprintf("%s (%d岁) - %s %s", s.Name, s.Age, s.School, s.Grade) +}// 实际应用 +示例 + +// 银行账户 +type BankAccount struct { + AccountNumber string + Balance float64 + Owner string +} + +func (ba *BankAccount) Deposit(amount float64) { + if amount > 0 { + ba.Balance += amount + fmt.Printf(" 存款 %.2f,当前余额: %.2f\n", amount, ba.Balance) + } +} + +func (ba *BankAccount) Withdraw(amount float64) bool { + if amount > 0 && amount <= ba.Balance { + ba.Balance -= amount + fmt.Printf(" 取款 %.2f,当前余额: %.2f\n", amount, ba.Balance) + return true + } + fmt.Printf(" 取款失败:余额不足或金额无效\n") + return false +} + +func (ba BankAccount) GetInfo() string { + return fmt.Sprintf("账户: %s, 户主: %s, 余额: %.2f", + ba.AccountNumber, ba.Owner, ba.Balance) +} + +// 购物车系统 +type CartItem struct { + Name string + Price float64 + Quantity int +} + +type ShoppingCart struct { + Items []CartItem +} + +func (sc *ShoppingCart) AddItem(name string, price float64, quantity int) { + // 检查是否已存在该商品 + for i := range sc.Items { + if sc.Items[i].Name == name { + sc.Items[i].Quantity += quantity + return + } + } + // 添加新商品 + sc.Items = append(sc.Items, CartItem{ + Name: name, + Price: price, + Quantity: quantity, + }) +} + +func (sc *ShoppingCart) RemoveItem(name string) { + for i, item := range sc.Items { + if item.Name == name { + sc.Items = append(sc.Items[:i], sc.Items[i+1:]...) + return + } + } +} + +func (sc ShoppingCart) GetTotal() float64 { + total := 0.0 + for _, item := range sc.Items { + total += item.Price * float64(item.Quantity) + } + return total +} + +func (sc ShoppingCart) DisplayItems() { + for _, item := range sc.Items { + fmt.Printf(" %s: %.2f × %d = %.2f\n", + item.Name, item.Price, item.Quantity, + item.Price*float64(item.Quantity)) + } +} + +// 日志记录器 +type Logger struct { + Level string +} + +func (l *Logger) SetLevel(level string) { + l.Level = level +} + +func (l Logger) shouldLog(level string) bool { + levels := map[string]int{ + "DEBUG": 0, + "INFO": 1, + "WARN": 2, + "ERROR": 3, + } + + currentLevel := levels[l.Level] + messageLevel := levels[level] + + return messageLevel >= currentLevel +} + +func (l Logger) log(level, message string) { + if l.shouldLog(level) { + timestamp := time.Now().Format("2006-01-02 15:04:05") + fmt.Printf(" [%s] %s: %s\n", timestamp, level, message) + } +} + +func (l Logger) Debug(message string) { + l.log("DEBUG", message) +} + +func (l Logger) Info(message string) { + l.log("INFO", message) +} + +func (l Logger) Warning(message string) { + l.log("WARN", message) +} + +func (l Logger) Error(message string) { + l.log("ERROR", message) +} + +// 配置管理器 +type Config struct { + settings map[string]string +} + +func (c *Config) Set(key, value string) { + c.settings[key] = value +} + +func (c Config) Get(key string) string { + if value, exists := c.settings[key]; exists { + return value + } + return "" +} + +func (c Config) DisplayAll() { + for key, value := range c.settings { + fmt.Printf(" %s = %s\n", key, value) + } +} + +// 计算器 +type Calculator struct{} + +func (calc Calculator) Add(a, b float64) float64 { + return a + b +} + +func (calc Calculator) Subtract(a, b float64) float64 { + return a - b +} + +func (calc Calculator) Multiply(a, b float64) float64 { + return a * b +} + +func (calc Calculator) Divide(a, b float64) float64 { + if b != 0 { + return a / b + } + return 0 +} + +// 字符串构建器(链式调用) +type StringBuilder struct { + parts []string +} + +func NewStringBuilder() *StringBuilder { + return &StringBuilder{parts: make([]string, 0)} +} + +func (sb *StringBuilder) Append(str string) *StringBuilder { + sb.parts = append(sb.parts, str) + return sb +} + +func (sb *StringBuilder) ToUpper() *StringBuilder { + for i, part := range sb.parts { + sb.parts[i] = strings.ToUpper(part) + } + return sb +} + +func (sb *StringBuilder) Build() string { + return strings.Join(sb.parts, "") +} + +/* +运行这个程序: +go run 05-methods.go + +学习要点: +1. 方法是与特定类型关联的函数 +2. 方法定义语法:func (receiver Type) MethodName() ReturnType +3. 值接收者和指针接收者有不同的行为和用途 +4. 方法集决定了类型可以实现哪些接口 +5. 结构体嵌入可以实现方法的继承和组合 + +方法 vs 函数: +1. 方法有接收者,函数没有 +2. 方法属于特定类型,函数是独立的 +3. 方法可以访问接收者的字段和其他方法 +4. 方法支持多态(通过接口) + +接收者类型选择: +1. 值接收者: + - 不需要修改接收者 + - 接收者是小的结构体 + - 接收者是基本类型、数组或小的结构体 + +2. 指针接收者: + - 需要修改接收者 + - 接收者是大的结构体(避免拷贝) + - 接收者包含不能拷贝的字段(如 sync.Mutex) + +方法集规则: +1. 值类型 T 的方法集:所有值接收者方法 +2. 指针类型 *T 的方法集:所有值接收者和指针接收者方法 +3. 接口实现需要考虑方法集的匹配 + +最佳实践: +1. 保持接收者类型的一致性 +2. 优先使用指针接收者(除非有特殊原因) +3. 合理使用结构体嵌入实现代码复用 +4. 设计清晰的接口和方法签名 +5. 使用方法实现面向对象的设计模式 + +常见应用场景: +1. 数据封装和操作 +2. 业务逻辑实现 +3. 接口实现和多态 +4. 链式调用和流畅接口 +5. 状态管理 +6. 配置和选项处理 + +高级特性: +1. 方法表达式和方法值 +2. 接口组合 +3. 类型断言 +4. 动态方法调用 +5. 链式方法调用 +*/ \ No newline at end of file diff --git a/golang-learning/03-functions/README.md b/golang-learning/03-functions/README.md new file mode 100644 index 0000000..ec2b96e --- /dev/null +++ b/golang-learning/03-functions/README.md @@ -0,0 +1,16 @@ +# 第三章:函数和方法 + +本章将学习 Go 语言的函数定义、调用以及方法的概念。 + +## 学习目标 +- 掌握函数的定义和调用 +- 理解多返回值的概念 +- 学会使用可变参数 +- 了解闭包和方法 + +## 文件列表 +- `01-basic-functions.go` - 基础函数 +- `02-multiple-returns.go` - 多返回值 +- `03-variadic-functions.go` - 可变参数函数 +- `04-closures.go` - 闭包 +- `05-methods.go` - 方法 \ No newline at end of file diff --git a/golang-learning/04-data-structures/01-arrays.go b/golang-learning/04-data-structures/01-arrays.go new file mode 100644 index 0000000..d3c8881 --- /dev/null +++ b/golang-learning/04-data-structures/01-arrays.go @@ -0,0 +1,199 @@ +/* +01-arrays.go - Go 语言数组详解 + +学习目标: +1. 理解数组的概念和特性 +2. 掌握数组的声明和初始化 +3. 学会数组的基本操作 +4. 了解数组的内存布局 +5. 掌握数组的实际应用场景 + +知识点: +- 数组的定义和特性 +- 数组的声明和初始化方式 +- 数组的访问和修改 +- 数组的长度和容量 +- 多维数组 +- 数组的比较和拷贝 +- 数组 vs 切片的区别 +*/ + +package main + +import "fmt" + +func main() { + fmt.Println("=== Go 语言数组详解 ===\n") + + // 演示数组的基本概念 + demonstrateBasicArrays() + + // 演示数组的声明和初始化 + demonstrateArrayDeclaration() + + // 演示数组的操作 + demonstrateArrayOperations() + + // 演示多维数组 + demonstrateMultiDimensionalArrays() + + // 演示数组的特性 + demonstrateArrayProperties() + + // 演示数组的实际应用 + demonstratePracticalApplications() + + // 演示数组 vs 切片 + demonstrateArrayVsSlice() +} + +// demonstrateBasicArrays 演示数组的基本概念 +func demonstrateBasicArrays() { + fmt.Println("1. 数组的基本概念:") + + // 数组的基本特性 + fmt.Printf(" 数组的基本特性:\n") + fmt.Printf(" - 固定长度的元素序列\n") + fmt.Printf(" - 元素类型相同\n") + fmt.Printf(" - 长度是类型的一部分\n") + fmt.Printf(" - 零值是所有元素都为零值的数组\n") + fmt.Printf(" - 值类型,赋值和传参会拷贝整个数组\n") + + // 基本数组示例 + fmt.Printf(" 基本数组示例:\n") + + var numbers [5]int // 声明长度为5的整数数组 + fmt.Printf(" 声明数组: %v\n", numbers) + fmt.Printf(" 数组长度: %d\n", len(numbers)) + fmt.Printf(" 数组类型: %T\n", numbers) + + // 数组元素访问 + numbers[0] = 10 + numbers[1] = 20 + numbers[2] = 30 + fmt.Printf(" 修改元素后: %v\n", numbers) + fmt.Printf(" 第一个元素: %d\n", numbers[0]) + fmt.Printf(" 最后一个元素: %d\n", numbers[len(numbers)-1]) + + fmt.Println() +} + +// demonstrateArrayDeclaration 演示数组的声明和初始化 +func demonstrateArrayDeclaration() { + fmt.Println("2. 数组的声明和初始化:") + + // 方式1: 声明后赋值 + fmt.Printf(" 方式1 - 声明后赋值:\n") + var arr1 [3]int + arr1[0] = 1 + arr1[1] = 2 + arr1[2] = 3 + fmt.Printf(" arr1: %v\n", arr1) + + // 方式2: 声明时初始化 + fmt.Printf(" 方式2 - 声明时初始化:\n") + var arr2 = [3]int{10, 20, 30} + fmt.Printf(" arr2: %v\n", arr2) + + // 方式3: 短变量声明 + fmt.Printf(" 方式3 - 短变量声明:\n") + arr3 := [4]string{"Go", "Python", "Java", "C++"} + fmt.Printf(" arr3: %v\n", arr3) + + // 方式4: 自动推断长度 + fmt.Printf(" 方式4 - 自动推断长度:\n") + arr4 := [...]int{1, 2, 3, 4, 5} // ... 让编译器计算长度 + fmt.Printf(" arr4: %v (长度: %d)\n", arr4, len(arr4)) + + // 方式5: 指定索引初始化 + fmt.Printf(" 方式5 - 指定索引初始化:\n") + arr5 := [5]int{1: 10, 3: 30, 4: 40} // 指定索引1,3,4的值 + fmt.Printf(" arr5: %v\n", arr5) + + // 方式6: 混合初始化 + fmt.Printf(" 方式6 - 混合初始化:\n") + arr6 := [...]string{0: "first", 2: "third", "fourth"} // 混合指定索引和顺序 + fmt.Printf(" arr6: %v (长度: %d)\n", arr6, len(arr6)) + + // 不同类型的数组 + fmt.Printf(" 不同类型的数组:\n") + boolArray := [3]bool{true, false, true} + floatArray := [4]float64{1.1, 2.2, 3.3, 4.4} + stringArray := [2]string{"hello", "world"} + + fmt.Printf(" 布尔数组: %v\n", boolArray) + fmt.Printf(" 浮点数组: %v\n", floatArray) + fmt.Printf(" 字符串数组: %v\n", stringArray) + + fmt.Println() +} + +// demonstrateArrayOperations 演示数组的操作 +func demonstrateArrayOperations() { + fmt.Println("3. 数组的操作:") + + // 数组遍历 + fmt.Printf(" 数组遍历:\n") + fruits := [4]string{"apple", "banana", "cherry", "date"} + + // 使用索引遍历 + fmt.Printf(" 使用索引遍历:\n") + for i := 0; i < len(fruits); i++ { + fmt.Printf(" fruits[%d] = %s\n", i, fruits[i]) + } + + // 使用 range 遍历 + fmt.Printf(" 使用 range 遍历:\n") + for index, value := range fruits { + fmt.Printf(" fruits[%d] = %s\n", index, value) + } + + // 只要值,忽略索引 + fmt.Printf(" 只要值,忽略索引:\n") + for _, fruit := range fruits { + fmt.Printf(" 水果: %s\n", fruit) + } + + // 只要索引,忽略值 + fmt.Printf(" 只要索引,忽略值:\n") + for index := range fruits { + fmt.Printf(" 索引: %d\n", index) + } + + // 数组修改 + fmt.Printf(" 数组修改:\n") + numbers := [5]int{1, 2, 3, 4, 5} + fmt.Printf(" 原始数组: %v\n", numbers) + + // 修改单个元素 + numbers[2] = 99 + fmt.Printf(" 修改索引2: %v\n", numbers) + + // 批量修改 + for i := range numbers { + numbers[i] *= 2 + } + fmt.Printf(" 全部乘以2: %v\n", numbers) + + // 数组查找 + fmt.Printf(" 数组查找:\n") + target := "cherry" + found := false + foundIndex := -1 + + for i, fruit := range fruits { + if fruit == target { + found = true + foundIndex = i + break + } + } + + if found { + fmt.Printf(" 找到 '%s' 在索引 %d\n", target, foundIndex) + } else { + fmt.Printf(" 未找到 '%s'\n", target) + } + + fmt.Println() +} \ No newline at end of file diff --git a/golang-learning/04-data-structures/README.md b/golang-learning/04-data-structures/README.md new file mode 100644 index 0000000..800a448 --- /dev/null +++ b/golang-learning/04-data-structures/README.md @@ -0,0 +1,16 @@ +# 第四章:数据结构 + +本章将学习 Go 语言的内置数据结构,包括数组、切片、映射、结构体和指针。 + +## 学习目标 +- 理解数组和切片的区别 +- 掌握映射的操作方法 +- 学会定义和使用结构体 +- 了解指针的概念和用法 + +## 文件列表 +- `01-arrays.go` - 数组 +- `02-slices.go` - 切片 +- `03-maps.go` - 映射 +- `04-structs.go` - 结构体 +- `05-pointers.go` - 指针 \ No newline at end of file diff --git a/golang-learning/05-interfaces/README.md b/golang-learning/05-interfaces/README.md new file mode 100644 index 0000000..7c0e52e --- /dev/null +++ b/golang-learning/05-interfaces/README.md @@ -0,0 +1,14 @@ +# 第五章:接口 + +本章将学习 Go 语言的接口系统,这是 Go 实现多态的重要机制。 + +## 学习目标 +- 理解接口的概念和作用 +- 掌握接口的定义和实现 +- 学会使用空接口 +- 了解类型断言的用法 + +## 文件列表 +- `01-basic-interfaces.go` - 基础接口 +- `02-empty-interface.go` - 空接口 +- `03-type-assertions.go` - 类型断言 \ No newline at end of file diff --git a/golang-learning/06-concurrency/README.md b/golang-learning/06-concurrency/README.md new file mode 100644 index 0000000..b63a9ec --- /dev/null +++ b/golang-learning/06-concurrency/README.md @@ -0,0 +1,17 @@ +# 第六章:并发编程 + +本章将学习 Go 语言最重要的特性之一:并发编程。 + +## 学习目标 +- 理解 goroutine 的概念 +- 掌握 channel 的使用 +- 学会使用 select 语句 +- 了解同步原语的用法 +- 掌握常见的并发模式 + +## 文件列表 +- `01-goroutines.go` - Goroutines +- `02-channels.go` - Channels +- `03-select.go` - Select 语句 +- `04-sync-package.go` - 同步包 +- `05-worker-pools.go` - 工作池模式 \ No newline at end of file diff --git a/golang-learning/07-error-handling/README.md b/golang-learning/07-error-handling/README.md new file mode 100644 index 0000000..3653484 --- /dev/null +++ b/golang-learning/07-error-handling/README.md @@ -0,0 +1,14 @@ +# 第七章:错误处理 + +本章将学习 Go 语言的错误处理机制,这是编写健壮程序的重要技能。 + +## 学习目标 +- 理解 Go 的错误处理哲学 +- 掌握基本的错误处理模式 +- 学会创建自定义错误 +- 了解 panic 和 recover 的用法 + +## 文件列表 +- `01-basic-errors.go` - 基础错误处理 +- `02-custom-errors.go` - 自定义错误 +- `03-panic-recover.go` - Panic 和 Recover \ No newline at end of file diff --git a/golang-learning/08-packages/README.md b/golang-learning/08-packages/README.md new file mode 100644 index 0000000..e7eb84b --- /dev/null +++ b/golang-learning/08-packages/README.md @@ -0,0 +1,14 @@ +# 第八章:包管理 + +本章将学习 Go 语言的包系统,包括如何创建、导入和管理包。 + +## 学习目标 +- 理解 Go 的包概念 +- 掌握包的创建和导入 +- 学会使用 Go Modules +- 了解包的可见性规则 + +## 文件列表 +- `01-creating-packages.go` - 创建包 +- `02-importing-packages.go` - 导入包 +- `utils/helper.go` - 示例包 \ No newline at end of file diff --git a/golang-learning/08-packages/utils/helper.go b/golang-learning/08-packages/utils/helper.go new file mode 100644 index 0000000..cffb6ec --- /dev/null +++ b/golang-learning/08-packages/utils/helper.go @@ -0,0 +1,33 @@ +// Package utils 提供一些实用的辅助函数 +// 这是一个示例包,用于演示包的创建和使用 +package utils + +import "fmt" + +// Add 计算两个整数的和 +// 注意:函数名首字母大写,表示这是一个导出的(公开的)函数 +func Add(a, b int) int { + return a + b +} + +// Multiply 计算两个整数的乘积 +func Multiply(a, b int) int { + return a * b +} + +// greet 是一个私有函数(首字母小写) +// 只能在包内部使用,外部无法访问 +func greet(name string) string { + return fmt.Sprintf("Hello, %s!", name) +} + +// GetGreeting 是一个公开函数,内部调用私有函数 +func GetGreeting(name string) string { + return greet(name) +} + +// 包级别的变量 +var PackageVersion = "1.0.0" + +// 包级别的常量 +const MaxRetries = 3 \ No newline at end of file diff --git a/golang-learning/09-advanced/README.md b/golang-learning/09-advanced/README.md new file mode 100644 index 0000000..2602322 --- /dev/null +++ b/golang-learning/09-advanced/README.md @@ -0,0 +1,15 @@ +# 第九章:高级特性 + +本章将学习 Go 语言的一些高级特性,包括反射、泛型、上下文和测试。 + +## 学习目标 +- 了解反射的基本概念和用法 +- 理解泛型的语法和应用 +- 掌握 context 包的使用 +- 学会编写单元测试 + +## 文件列表 +- `01-reflection.go` - 反射 +- `02-generics.go` - 泛型 +- `03-context.go` - Context +- `04-testing.go` - 测试 \ No newline at end of file diff --git a/golang-learning/10-projects/01-calculator/README.md b/golang-learning/10-projects/01-calculator/README.md new file mode 100644 index 0000000..5007f48 --- /dev/null +++ b/golang-learning/10-projects/01-calculator/README.md @@ -0,0 +1,24 @@ +# 计算器项目 + +一个支持基本四则运算的命令行计算器程序。 + +## 功能特性 +- 支持加法、减法、乘法、除法 +- 错误处理(如除零错误) +- 交互式命令行界面 +- 输入验证 + +## 运行方法 +```bash +cd 01-calculator +go run main.go +``` + +## 使用示例 +``` +欢迎使用 Go 计算器! +请输入第一个数字: 10 +请选择运算符 (+, -, *, /): + +请输入第二个数字: 5 +结果: 10 + 5 = 15 +``` \ No newline at end of file diff --git a/golang-learning/10-projects/02-todo-list/README.md b/golang-learning/10-projects/02-todo-list/README.md new file mode 100644 index 0000000..2d7eb0d --- /dev/null +++ b/golang-learning/10-projects/02-todo-list/README.md @@ -0,0 +1,31 @@ +# 待办事项列表项目 + +一个命令行待办事项管理程序,支持添加、删除、标记完成等功能。 + +## 功能特性 +- 添加新的待办事项 +- 查看所有待办事项 +- 标记事项为完成 +- 删除待办事项 +- 数据持久化(保存到文件) + +## 运行方法 +```bash +cd 02-todo-list +go run main.go +``` + +## 使用示例 +```bash +# 添加待办事项 +go run main.go add "学习 Go 语言" + +# 查看所有事项 +go run main.go list + +# 标记完成 +go run main.go complete 1 + +# 删除事项 +go run main.go delete 1 +``` \ No newline at end of file diff --git a/golang-learning/10-projects/03-web-server/README.md b/golang-learning/10-projects/03-web-server/README.md new file mode 100644 index 0000000..0e879f9 --- /dev/null +++ b/golang-learning/10-projects/03-web-server/README.md @@ -0,0 +1,38 @@ +# Web 服务器项目 + +一个简单的 HTTP Web 服务器,提供 RESTful API。 + +## 功能特性 +- HTTP 服务器 +- RESTful API 端点 +- JSON 数据处理 +- 路由处理 +- 中间件支持 +- 静态文件服务 + +## API 端点 +- `GET /` - 首页 +- `GET /api/users` - 获取用户列表 +- `POST /api/users` - 创建新用户 +- `GET /api/users/{id}` - 获取特定用户 +- `PUT /api/users/{id}` - 更新用户 +- `DELETE /api/users/{id}` - 删除用户 + +## 运行方法 +```bash +cd 03-web-server +go run main.go +``` + +服务器将在 http://localhost:8080 启动 + +## 使用示例 +```bash +# 获取用户列表 +curl http://localhost:8080/api/users + +# 创建新用户 +curl -X POST http://localhost:8080/api/users \ + -H "Content-Type: application/json" \ + -d '{"name":"张三","email":"zhangsan@example.com"}' +``` \ No newline at end of file diff --git a/golang-learning/10-projects/README.md b/golang-learning/10-projects/README.md new file mode 100644 index 0000000..e7eafeb --- /dev/null +++ b/golang-learning/10-projects/README.md @@ -0,0 +1,43 @@ +# 第十章:实践项目 + +本章包含三个实践项目,帮助你综合运用前面学到的 Go 语言知识。 + +## 学习目标 +- 综合运用 Go 语言的各种特性 +- 学会项目结构的组织 +- 掌握实际开发中的最佳实践 +- 提高解决实际问题的能力 + +## 项目列表 + +### 1. 计算器 (01-calculator/) +一个支持基本四则运算的命令行计算器程序。 + +**涉及知识点:** +- 基础语法 +- 函数定义 +- 错误处理 +- 用户输入处理 + +### 2. 待办事项列表 (02-todo-list/) +一个命令行待办事项管理程序,支持添加、删除、标记完成等功能。 + +**涉及知识点:** +- 数据结构 +- 文件操作 +- JSON 序列化 +- 命令行参数处理 + +### 3. Web 服务器 (03-web-server/) +一个简单的 HTTP Web 服务器,提供 RESTful API。 + +**涉及知识点:** +- HTTP 服务器 +- 路由处理 +- JSON API +- 并发处理 +- 中间件 + +## 运行项目 + +每个项目目录下都有详细的 README.md 文件,包含运行说明和使用方法。 \ No newline at end of file diff --git a/golang-learning/README.md b/golang-learning/README.md new file mode 100644 index 0000000..05f8cc8 --- /dev/null +++ b/golang-learning/README.md @@ -0,0 +1,267 @@ +# Go 语言学习指南 + +欢迎来到 Go 语言学习之旅!这是一个专为初学者设计的系统化学习资源,通过实际代码示例帮助你掌握 Go 编程语言。 + +## 📚 学习目标 + +通过这个学习指南,你将能够: +- 掌握 Go 语言的基础语法和核心概念 +- 理解 Go 的并发编程模型 +- 学会使用 Go 的标准库 +- 编写结构良好、可维护的 Go 代码 +- 构建实际的 Go 应用程序 + +## 🗂️ 项目结构 + +``` +golang-learning/ +├── README.md # 本文件 - 学习指南 +├── go.mod # Go 模块文件 +├── 01-basics/ # 第一章:基础语法 +├── 02-control-flow/ # 第二章:控制流程 +├── 03-functions/ # 第三章:函数和方法 +├── 04-data-structures/ # 第四章:数据结构 +├── 05-interfaces/ # 第五章:接口 +├── 06-concurrency/ # 第六章:并发编程 +├── 07-error-handling/ # 第七章:错误处理 +├── 08-packages/ # 第八章:包管理 +├── 09-advanced/ # 第九章:高级特性 +└── 10-projects/ # 第十章:实践项目 +``` + +## 🎯 推荐学习路径 + +### 第一阶段:基础入门(1-2周) +**目标:掌握 Go 语言的基本语法** + +1. **[01-basics/](01-basics/)** - 基础语法 + - Hello World 程序 + - 变量声明和初始化 + - 常量定义 + - 基本数据类型 + - 运算符使用 + +2. **[02-control-flow/](02-control-flow/)** - 控制流程 + - 条件语句 (if/else) + - 分支语句 (switch) + - 循环语句 (for) + - 范围遍历 (range) + +### 第二阶段:函数和数据(2-3周) +**目标:学会组织代码和处理数据** + +3. **[03-functions/](03-functions/)** - 函数和方法 + - 函数定义和调用 + - 多返回值 + - 可变参数 + - 闭包 + - 方法 + +4. **[04-data-structures/](04-data-structures/)** - 数据结构 + - 数组 + - 切片 + - 映射 + - 结构体 + - 指针 + +### 第三阶段:面向对象(1-2周) +**目标:理解 Go 的接口系统** + +5. **[05-interfaces/](05-interfaces/)** - 接口 + - 接口定义和实现 + - 空接口 + - 类型断言 + +### 第四阶段:并发编程(2-3周) +**目标:掌握 Go 的并发特性** + +6. **[06-concurrency/](06-concurrency/)** - 并发编程 + - Goroutines + - Channels + - Select 语句 + - 同步原语 + - 工作池模式 + +### 第五阶段:工程实践(2-3周) +**目标:学会编写健壮的程序** + +7. **[07-error-handling/](07-error-handling/)** - 错误处理 + - 基本错误处理 + - 自定义错误 + - Panic 和 Recover + +8. **[08-packages/](08-packages/)** - 包管理 + - 创建包 + - 导入包 + - Go Modules + +### 第六阶段:高级特性(2-3周) +**目标:掌握高级编程技巧** + +9. **[09-advanced/](09-advanced/)** - 高级特性 + - 反射 + - 泛型 + - Context + - 测试 + +### 第七阶段:实践项目(3-4周) +**目标:综合运用所学知识** + +10. **[10-projects/](10-projects/)** - 实践项目 + - 计算器 + - 待办事项列表 + - Web 服务器 + +## 🚀 如何使用这个学习指南 + +### 1. 环境准备 +确保你已经安装了 Go 语言环境: +```bash +# 检查 Go 版本 +go version + +# 如果没有安装,请访问 https://golang.org/dl/ 下载安装 +``` + +### 2. 克隆或下载项目 +```bash +# 如果你有 Git +git clone +cd golang-learning + +# 或者直接下载并解压项目文件 +``` + +### 3. 开始学习 +```bash +# 进入第一个学习模块 +cd 01-basics + +# 运行第一个示例 +go run 01-hello-world.go +``` + +### 4. 学习方法建议 + +**📖 阅读代码** +- 仔细阅读每个文件的注释 +- 理解每行代码的作用 +- 注意代码的组织结构 + +**🏃‍♂️ 运行示例** +- 运行每个 .go 文件 +- 观察输出结果 +- 对比预期和实际输出 + +**✏️ 动手实践** +- 修改示例代码 +- 尝试不同的参数 +- 观察结果变化 + +**🤔 思考总结** +- 理解每个概念的用途 +- 思考实际应用场景 +- 记录学习笔记 + +## 📋 学习检查清单 + +在每个模块学习完成后,确保你能够: + +### 01-basics 基础语法 +- [ ] 能够编写和运行 Hello World 程序 +- [ ] 理解变量声明的不同方式 +- [ ] 掌握 Go 的基本数据类型 +- [ ] 会使用各种运算符 + +### 02-control-flow 控制流程 +- [ ] 能够使用 if/else 进行条件判断 +- [ ] 掌握 switch 语句的用法 +- [ ] 理解 for 循环的各种形式 +- [ ] 会使用 range 遍历数据 + +### 03-functions 函数和方法 +- [ ] 能够定义和调用函数 +- [ ] 理解多返回值的概念 +- [ ] 掌握可变参数的使用 +- [ ] 理解闭包和方法 + +### 04-data-structures 数据结构 +- [ ] 掌握数组和切片的区别 +- [ ] 能够操作映射(map) +- [ ] 理解结构体的定义和使用 +- [ ] 掌握指针的概念 + +### 05-interfaces 接口 +- [ ] 理解接口的概念 +- [ ] 能够定义和实现接口 +- [ ] 掌握类型断言的使用 + +### 06-concurrency 并发编程 +- [ ] 理解 goroutine 的概念 +- [ ] 能够使用 channel 进行通信 +- [ ] 掌握 select 语句的用法 +- [ ] 了解同步原语的使用 + +### 07-error-handling 错误处理 +- [ ] 掌握 Go 的错误处理模式 +- [ ] 能够创建自定义错误 +- [ ] 理解 panic 和 recover + +### 08-packages 包管理 +- [ ] 能够创建和使用包 +- [ ] 理解 Go Modules 的概念 +- [ ] 掌握包的导入和导出 + +### 09-advanced 高级特性 +- [ ] 了解反射的基本用法 +- [ ] 理解泛型的概念 +- [ ] 掌握 context 的使用 +- [ ] 能够编写单元测试 + +### 10-projects 实践项目 +- [ ] 完成计算器项目 +- [ ] 完成待办事项列表项目 +- [ ] 完成 Web 服务器项目 + +## 🔗 扩展资源 + +### 官方资源 +- [Go 官方网站](https://golang.org/) +- [Go 官方文档](https://golang.org/doc/) +- [Go 标准库文档](https://pkg.go.dev/std) +- [Go 语言规范](https://golang.org/ref/spec) + +### 推荐书籍 +- 《Go 程序设计语言》 +- 《Go 语言实战》 +- 《Go 语言学习笔记》 + +### 在线资源 +- [Go by Example](https://gobyexample.com/) +- [A Tour of Go](https://tour.golang.org/) +- [Go 语言中文网](https://studygolang.com/) + +## 💡 学习建议 + +1. **循序渐进**:按照推荐的学习路径,不要跳跃式学习 +2. **多动手**:理论结合实践,多写代码 +3. **多思考**:理解概念背后的原理 +4. **多交流**:加入 Go 语言社区,与其他学习者交流 +5. **持续练习**:定期回顾和练习已学内容 + +## 🤝 贡献 + +如果你发现任何问题或有改进建议,欢迎: +- 提交 Issue +- 发起 Pull Request +- 分享你的学习心得 + +## 📄 许可证 + +本项目采用 MIT 许可证,详见 LICENSE 文件。 + +--- + +**祝你学习愉快!🎉** + +记住:学习编程最重要的是坚持和实践。每天进步一点点,你就能掌握 Go 语言! \ No newline at end of file diff --git a/golang-learning/go.mod b/golang-learning/go.mod new file mode 100644 index 0000000..a646a4d --- /dev/null +++ b/golang-learning/go.mod @@ -0,0 +1,3 @@ +module golang-learning + +go 1.21 \ No newline at end of file