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