diff --git a/chapters/chapter-2-basics.md b/chapters/chapter-2-basics.md new file mode 100644 index 0000000..a4b5f67 --- /dev/null +++ b/chapters/chapter-2-basics.md @@ -0,0 +1,896 @@ +# 第二章:Go 基础语法 —— 变量、类型与流程控制 + +> **本章目标**:深入理解 Go 的变量声明机制、核心数据类型、运算符体系及流程控制结构,掌握 Go 独特的"零值"哲学和"类型推断"特性。 + +## 2.1 Go 的变量声明机制 + +Go 语言的变量声明方式灵活多样,理解其背后的机制是编写高效代码的基础。 + +### 2.1.1 四种声明方式 + +#### 1. `var` 声明(显式类型) + +```go +var name string = "Alice" +var age int = 25 +var isActive bool = true +``` + +**深度解析**: +- `var` 是 Go 中**最正式**的声明方式 +- 可以省略初始化,此时变量会被赋予**零值**(见 2.2 节) +- 支持在函数内外声明(包级变量和局部变量) + +#### 2. `var` 声明(类型推断) + +```go +var name = "Bob" // 编译器推断为 string +var count = 100 // 编译器推断为 int +var ratio = 3.14 // 编译器推断为 float64 +``` + +**深度解析**: +- 当提供初始值时,Go 编译器会自动推断类型 +- 这是**推荐**的声明方式,代码更简洁 +- 类型一旦推断,不可更改(Go 是静态类型语言) + +#### 3. 短变量声明 `:=`(最常用) + +```go +name := "Charlie" +age := 30 +isValid := true +``` + +**深度解析**: +- `:=` 是 `var` + 类型推断的**语法糖** +- **只能在函数内部使用**(不能在包级作用域使用) +- 如果变量已存在,会**重新赋值**而非声明新变量 +- 可以混合新旧变量:`a, b := 1, 2`(即使 `a` 已存在) + +```go +// 错误示例:包级作用域不能使用 := +package main + +// x := 10 // 编译错误! + +func main() { + y := 20 // 正确 +} +``` + +#### 4. 多变量声明 + +```go +// 显式类型 +var ( + name string = "David" + age int = 28 +) + +// 类型推断 +var ( + city = "Beijing" + score = 95.5 +) + +// 短声明 +x, y, z := 1, 2, 3 +``` + +**深度解析**: +- 使用 `var ()` 块可以批量声明变量,适合包级变量 +- 短声明 `:=` 支持多个变量同时声明 +- **注意**:`:=` 左侧至少有一个变量是新的,否则是赋值操作 + +```go +a, b := 1, 2 // 声明两个新变量 +a, c := 3, 4 // a 已存在,c 是新变量(合法) +a, b := 5, 6 // a 和 b 都已存在,编译错误! +``` + +### 2.1.2 变量作用域 + +Go 的作用域规则非常清晰: + +```go +package main + +import "fmt" + +// 包级变量(全局作用域) +var globalVar = "I am global" + +func main() { + // 函数级变量 + localVar := "I am local" + + if true { + // 块级变量(if 块内) + blockVar := "I am in if block" + fmt.Println(blockVar) + } + + // fmt.Println(blockVar) // 编译错误!blockVar 在 if 块外不可见 + + fmt.Println(localVar) + fmt.Println(globalVar) +} +``` + +**深度解析**: +- **包级作用域**:在 `package` 声明后,任何函数外声明的变量 +- **函数作用域**:在函数内部声明的变量 +- **块级作用域**:在 `{}` 代码块内声明的变量(if、for、switch 等) +- 内层作用域可以**遮蔽**外层同名变量 + +```go +func shadowExample() { + x := 10 + if true { + x := 20 // 创建了新变量 x,遮蔽了外层的 x + fmt.Println(x) // 输出 20 + } + fmt.Println(x) // 输出 10(外层 x 未受影响) +} +``` + +## 2.2 Go 的"零值"哲学 + +Go 语言有一个非常优雅的设计:**未初始化的变量会自动获得零值**。 + +### 2.2.1 零值表 + +| 类型 | 零值 | 说明 | +|------|------|------| +| `int`, `int8`, `int16`, `int32`, `int64` | `0` | 整数类型 | +| `uint`, `uint8`, `uint16`, `uint32`, `uint64` | `0` | 无符号整数 | +| `float32`, `float64` | `0.0` | 浮点数 | +| `complex64`, `complex128` | `0 + 0i` | 复数 | +| `bool` | `false` | 布尔值 | +| `string` | `""` | 空字符串 | +| 指针、函数、接口、切片、映射、通道 | `nil` | 引用类型 | +| 数组 | 数组元素全为零值 | 值类型 | + +### 2.2.2 零值的实际意义 + +```go +package main + +import "fmt" + +func main() { + var intVar int + var floatVar float64 + var boolVar bool + var stringVar string + var ptrVar *int + + fmt.Printf("int: %d\n", intVar) // 0 + fmt.Printf("float: %f\n", floatVar) // 0.000000 + fmt.Printf("bool: %v\n", boolVar) // false + fmt.Printf("string: '%s'\n", stringVar) // '' + fmt.Printf("ptr: %v\n", ptrVar) // + + // 零值判断 + if stringVar == "" { + fmt.Println("字符串为空") + } + + if ptrVar == nil { + fmt.Println("指针为空") + } +} +``` + +**深度解析**: +- 零值机制避免了"未初始化变量"的运行时错误 +- 在结构体中,未设置的字段自动为零值 +- 这是 Go 语言**安全性**的重要体现 + +```go +type User struct { + Name string + Age int + Email string +} + +func main() { + u := User{} // 所有字段为零值 + fmt.Printf("%+v\n", u) // {Name: Age:0 Email:} + + // 零值判断 + if u.Name == "" { + fmt.Println("用户未设置名称") + } +} +``` + +## 2.3 核心数据类型详解 + +### 2.3.1 整型(Integer Types) + +Go 提供了多种整型,适应不同场景: + +```go +var ( + a int8 // 8 位有符号整数,范围:-128 ~ 127 + b int16 // 16 位有符号整数,范围:-32768 ~ 32767 + c int32 // 32 位有符号整数,范围:-2147483648 ~ 2147483647 + d int64 // 64 位有符号整数,范围:-9223372036854775808 ~ 9223372036854775807 + + e uint8 // 8 位无符号整数,范围:0 ~ 255 + f uint16 // 16 位无符号整数,范围:0 ~ 65535 + g uint32 // 32 位无符号整数,范围:0 ~ 4294967295 + h uint64 // 64 位无符号整数,范围:0 ~ 18446744073709551615 + + i int // 平台相关:32 位系统为 int32,64 位系统为 int64 + j uint // 平台相关:32 位系统为 uint32,64 位系统为 uint64 +) +``` + +**深度解析**: +- `int` 和 `uint` 的大小取决于**平台架构**(32 位或 64 位) +- 优先使用 `int` 和 `int64`,除非有特殊内存优化需求 +- `byte` 是 `uint8` 的别名,常用于处理二进制数据 +- `rune` 是 `int32` 的别名,用于表示 Unicode 字符 + +```go +package main + +import "fmt" + +func main() { + var b byte = 'A' // byte 是 uint8 的别名 + var r rune = '中' // rune 是 int32 的别名,可存储 Unicode 字符 + + fmt.Printf("byte: %c, %d\n", b, b) // A, 65 + fmt.Printf("rune: %c, %d\n", r, r) // 中,20013 + + // 字节数测试 + fmt.Printf("len('A'): %d\n", len("A")) // 1 + fmt.Printf("len('中'): %d\n", len("中")) // 3(UTF-8 编码占 3 字节) +} +``` + +### 2.3.2 浮点型(Floating-Point Types) + +```go +var ( + a float32 = 3.14 + b float64 = 3.141592653589793 +) +``` + +**深度解析**: +- `float64` 是**默认**浮点类型,精度更高 +- `float32` 节省内存,适合对精度要求不高的场景(如图形处理) +- 浮点数比较时注意精度问题 + +```go +package main + +import "fmt" +import "math" + +func main() { + a := 0.1 + 0.2 + b := 0.3 + + fmt.Printf("a == b: %v\n", a == b) // false(精度问题) + fmt.Printf("a: %.20f\n", a) // 0.30000000000000004441 + + // 正确比较方式 + epsilon := 1e-9 + if math.Abs(a-b) < epsilon { + fmt.Println("a 和 b 近似相等") + } +} +``` + +### 2.3.3 复数类型(Complex Types) + +```go +var ( + c1 complex64 = 1 + 2i + c2 complex128 = 3.5 + 4.5i +) +``` + +**深度解析**: +- `i` 或 `j` 表示虚部 +- 较少使用,主要用于科学计算和信号处理 + +### 2.3.4 布尔类型(Boolean Type) + +```go +var ( + isTrue bool = true + isFalse bool = false +) +``` + +**深度解析**: +- 只有 `true` 和 `false` 两个值 +- **不能**与整数互相转换(`0` 不等于 `false`) +- 逻辑运算符:`&&`(与)、`||`(或)、`!`(非) + +```go +package main + +import "fmt" + +func main() { + a, b := true, false + + fmt.Printf("a && b: %v\n", a && b) // false + fmt.Printf("a || b: %v\n", a || b) // true + fmt.Printf("!a: %v\n", !a) // false + + // 短路求值 + if false && someExpensiveFunction() { + // someExpensiveFunction() 不会被执行 + } +} +``` + +### 2.3.5 字符串类型(String Type) + +```go +var s1 string = "Hello" +var s2 string = "世界" +var s3 string = `多行 +字符串` +``` + +**深度解析**: +- 字符串是**不可变**的字节序列(UTF-8 编码) +- 使用双引号 `"` 或反引号 `` ` `` +- 反引号表示**原始字符串**,不转义任何字符 +- 字符串长度使用 `len()`,但返回的是**字节数**而非字符数 + +```go +package main + +import "fmt" + +func main() { + s := "Hello 世界" + + fmt.Printf("len(s): %d\n", len(s)) // 11(字节数) + fmt.Printf("s[0]: %c\n", s[0]) // H + // fmt.Printf("s[6]: %c\n", s[6]) // 可能乱码(中文字符占 3 字节) + + // 遍历字符串(按 rune) + for i, r := range s { + fmt.Printf("位置 %d: 字符 %c (Unicode: %d)\n", i, r, r) + } + + // 字符串拼接 + s1 := "Hello" + s2 := "World" + s3 := s1 + " " + s2 + + // 使用 strings.Builder(高性能拼接) + var builder strings.Builder + builder.WriteString("Hello") + builder.WriteString(" ") + builder.WriteString("World") + fmt.Println(builder.String()) +} +``` + +**注意**:需要导入 `strings` 包。 + +## 2.4 类型转换与类型推断 + +### 2.4.1 显式类型转换 + +Go **不支持**隐式类型转换,必须显式转换: + +```go +package main + +import "fmt" + +func main() { + var a int = 42 + var b float64 = float64(a) // 显式转换 + var c int = int(b) // 显式转换 + + fmt.Printf("a: %d, type: %T\n", a, a) + fmt.Printf("b: %f, type: %T\n", b, b) + fmt.Printf("c: %d, type: %T\n", c, c) + + // 错误示例:隐式转换(编译错误) + // var x int = 3.14 // 编译错误! +} +``` + +**深度解析**: +- 转换必须在**兼容类型**之间进行 +- 转换可能导致**精度丢失**或**溢出** +- 使用 `int64(float64)` 转换时注意范围检查 + +```go +package main + +import "fmt" +import "math" + +func main() { + var f float64 = 1.9 + var i int = int(f) // 截断小数部分,结果为 1 + + fmt.Printf("int(1.9): %d\n", i) // 1 + + // 四舍五入 + i = int(math.Round(f)) + fmt.Printf("round(1.9): %d\n", i) // 2 + + // 溢出检查 + var largeFloat float64 = 1e20 + var smallInt int = int(largeFloat) // 可能溢出 + fmt.Printf("largeFloat -> int: %d\n", smallInt) +} +``` + +### 2.4.2 类型推断的边界 + +```go +package main + +import "fmt" + +func main() { + // 类型推断 + a := 10 // int + b := 3.14 // float64 + c := "hello" // string + d := true // bool + + // 无法推断(需要显式类型) + var e // 编译错误!必须提供类型或初始值 + + // 混合推断 + f, g, h := 1, 2.5, "test" + fmt.Printf("f: %T, g: %T, h: %T\n", f, g, h) +} +``` + +## 2.5 运算符体系 + +### 2.5.1 算术运算符 + +```go +a, b := 10, 3 + +// 加法、减法、乘法、除法、取余 +sum := a + b // 13 +diff := a - b // 7 +product := a * b // 30 +quotient := a / b // 3(整数除法) +remainder := a % b // 1 + +// 注意:整数除法会截断小数部分 +fmt.Printf("10 / 3 = %d\n", 10/3) // 3 +fmt.Printf("10.0 / 3.0 = %f\n", 10.0/3.0) // 3.333333 +``` + +### 2.5.2 比较运算符 + +```go +a, b := 10, 20 + +// 等于、不等于、大于、小于、大于等于、小于等于 +fmt.Println(a == b) // false +fmt.Println(a != b) // true +fmt.Println(a > b) // false +fmt.Println(a < b) // true +fmt.Println(a >= b) // false +fmt.Println(a <= b) // true +``` + +**注意**:字符串也可以比较(按字典序): +```go +fmt.Println("apple" < "banana") // true +``` + +### 2.5.3 逻辑运算符 + +```go +a, b := true, false + +fmt.Println(a && b) // false(与) +fmt.Println(a || b) // true(或) +fmt.Println(!a) // false(非) +``` + +**短路求值**: +```go +func expensive() bool { + fmt.Println("expensive function called") + return true +} + +if false && expensive() { + // expensive() 不会被调用 +} +``` + +### 2.5.4 位运算符 + +```go +a, b := 6, 3 // 6 = 110, 3 = 011 + +fmt.Printf("a & b: %d\n", a & b) // 2 (010) +fmt.Printf("a | b: %d\n", a | b) // 7 (111) +fmt.Printf("a ^ b: %d\n", a ^ b) // 5 (101) +fmt.Printf("a &^ b: %d\n", a &^ b) // 4 (100) 位清除 +fmt.Printf("a << 1: %d\n", a << 1) // 12 (1100) +fmt.Printf("a >> 1: %d\n", a >> 1) // 3 (011) +``` + +### 2.5.5 赋值运算符 + +```go +a := 10 + +a += 5 // a = a + 5 +a -= 3 // a = a - 3 +a *= 2 // a = a * 2 +a /= 4 // a = a / 4 +a %= 3 // a = a % 3 + +a &= 1 // a = a & 1 +a |= 2 // a = a | 2 +a ^= 4 // a = a ^ 4 +a <<= 1 // a = a << 1 +a >>= 1 // a = a >> 1 +``` + +## 2.6 流程控制 + +### 2.6.1 if-else 语句 + +```go +score := 85 + +if score >= 90 { + fmt.Println("优秀") +} else if score >= 80 { + fmt.Println("良好") +} else if score >= 60 { + fmt.Println("及格") +} else { + fmt.Println("不及格") +} +``` + +**深度解析**: +- `if` 条件前可以有一个**简短语句** +- 简短语句的作用域仅限于 `if-else` 块 + +```go +if x := computeValue(); x > 0 { + fmt.Println("x 为正数:", x) +} else { + fmt.Println("x 为非正数:", x) +} +// fmt.Println(x) // 编译错误!x 在 if 块外不可见 +``` + +### 2.6.2 switch 语句 + +```go +day := 3 + +switch day { +case 1: + fmt.Println("星期一") +case 2: + fmt.Println("星期二") +case 3, 4, 5: + fmt.Println("工作日") +case 6, 7: + fmt.Println("周末") +default: + fmt.Println("无效日期") +} +``` + +**深度解析**: +- `switch` 默认包含 `break`,不需要手动写 +- 可以使用 `fallthrough` 继续执行下一个 case +- 支持**无表达式**的 switch(类似 if-else 链) + +```go +// 多值 case +switch day { +case 1, 2, 3, 4, 5: + fmt.Println("工作日") +case 6, 7: + fmt.Println("周末") +} + +// fallthrough +switch day { +case 1: + fmt.Println("星期一") + fallthrough // 继续执行 case 2 +case 2: + fmt.Println("星期二(包含星期一)") +} + +// 无表达式 switch +switch { +case score >= 90: + fmt.Println("优秀") +case score >= 80: + fmt.Println("良好") +default: + fmt.Println("其他") +} +``` + +### 2.6.3 for 循环 + +Go 只有 `for` 一种循环结构,但功能强大: + +```go +// 1. 传统 for 循环 +for i := 0; i < 5; i++ { + fmt.Println(i) +} + +// 2. while 风格(省略初始化) +i := 0 +for i < 5 { + fmt.Println(i) + i++ +} + +// 3. 无限循环 +for { + // ... + break // 必须退出 +} + +// 4. range 遍历 +slice := []int{1, 2, 3, 4, 5} +for index, value := range slice { + fmt.Printf("索引 %d: 值 %d\n", index, value) +} + +// 5. 只遍历索引 +for i := range slice { + fmt.Println(i) +} + +// 6. 只遍历值(使用 _ 忽略索引) +for _, v := range slice { + fmt.Println(v) +} +``` + +**深度解析**: +- `range` 遍历字符串时,返回的是 **rune(Unicode 字符)** 而非字节 +- `for` 循环的初始化语句中的变量,作用域仅限于循环 + +```go +// 字符串遍历 +s := "Hello" +for i, r := range s { + fmt.Printf("位置 %d: 字符 %c\n", i, r) +} + +// 作用域测试 +for i := 0; i < 3; i++ { + fmt.Println(i) +} +// fmt.Println(i) // 编译错误!i 在循环外不可见 +``` + +### 2.6.4 break 和 continue + +```go +// break:跳出当前循环 +for i := 0; i < 10; i++ { + if i == 5 { + break + } + fmt.Println(i) // 输出 0-4 +} + +// continue:跳过本次循环 +for i := 0; i < 10; i++ { + if i%2 == 0 { + continue + } + fmt.Println(i) // 输出 1, 3, 5, 7, 9 +} + +// 带标签的 break/continue(跳出多层循环) +outer: +for i := 0; i < 3; i++ { + for j := 0; j < 3; j++ { + if i == 1 && j == 1 { + break outer // 跳出外层循环 + } + fmt.Printf("i=%d, j=%d\n", i, j) + } +} +``` + +## 2.7 深度实践:综合案例 + +### 2.7.1 简易计算器 + +```go +package main + +import ( + "fmt" + "strconv" +) + +func main() { + var num1, num2 float64 + var operator string + + fmt.Print("请输入第一个数字:") + fmt.Scan(&num1) + + fmt.Print("请输入运算符 (+, -, *, /):") + fmt.Scan(&operator) + + fmt.Print("请输入第二个数字:") + fmt.Scan(&num2) + + var result float64 + var valid bool + + switch operator { + case "+": + result = num1 + num2 + valid = true + case "-": + result = num1 - num2 + valid = true + case "*": + result = num1 * num2 + valid = true + case "/": + if num2 == 0 { + fmt.Println("错误:除数不能为零") + valid = false + } else { + result = num1 / num2 + valid = true + } + default: + fmt.Println("错误:无效的运算符") + valid = false + } + + if valid { + fmt.Printf("结果:%.2f %s %.2f = %.2f\n", num1, operator, num2, result) + } +} +``` + +### 2.7.2 素数判断 + +```go +package main + +import "fmt" + +func isPrime(n int) bool { + if n <= 1 { + return false + } + if n == 2 { + return true + } + if n%2 == 0 { + return false + } + + // 只需检查到 sqrt(n) + for i := 3; i*i <= n; i += 2 { + if n%i == 0 { + return false + } + } + return true +} + +func main() { + fmt.Println("1 到 100 之间的素数:") + count := 0 + for i := 1; i <= 100; i++ { + if isPrime(i) { + fmt.Printf("%d ", i) + count++ + if count%10 == 0 { + fmt.Println() + } + } + } + fmt.Printf("\n共 %d 个素数\n", count) +} +``` + +## 2.8 常见陷阱与最佳实践 + +### 2.8.1 变量遮蔽陷阱 + +```go +func shadowBug() { + x := 10 + if true { + x := 20 // 创建了新变量,遮蔽了外层 x + fmt.Println(x) // 20 + } + fmt.Println(x) // 10(外层 x 未变) + + // 正确做法:使用 = 赋值 + if true { + x = 30 // 修改外层 x + fmt.Println(x) // 30 + } + fmt.Println(x) // 30 +} +``` + +### 2.8.2 整数除法陷阱 + +```go +// 错误:整数除法 +result := 5 / 2 // 结果为 2,而非 2.5 + +// 正确:使用浮点数 +result := 5.0 / 2.0 // 结果为 2.5 +// 或 +result := float64(5) / float64(2) +``` + +### 2.8.3 字符串长度陷阱 + +```go +s := "你好" +fmt.Println(len(s)) // 6(字节数,不是字符数) + +// 正确获取字符数 +runeCount := len([]rune(s)) // 2 +fmt.Println(runeCount) +``` + +### 2.8.4 最佳实践 + +1. **优先使用短声明 `:=`**,代码更简洁 +2. **利用零值**,减少不必要的初始化 +3. **避免变量遮蔽**,保持代码清晰 +4. **显式类型转换**,避免精度丢失 +5. **使用 `range` 遍历**,避免手动索引 +6. **注意字符串编码**,使用 `rune` 处理 Unicode + +## 2.9 课后练习 + +1. **变量声明**:用四种方式声明变量,体会它们的区别 +2. **零值测试**:创建各种类型的未初始化变量,观察它们的零值 +3. **类型转换**:编写程序测试整数到浮点数的转换,观察精度变化 +4. **字符串遍历**:遍历包含中文的字符串,输出每个字符及其 Unicode 码点 +5. **素数统计**:统计 1 到 1000 之间的素数个数 +6. **综合练习**:编写一个温度转换器(摄氏度 ↔ 华氏度) + +## 2.10 下一步 + +完成本章后,你将进入第三章:**数据结构详解**,深入学习数组、切片、映射和结构体,这是 Go 语言最核心的数据组织方式。 + +--- + +**代码仓库位置**:https://giter.top/openclaw/test/tree/main/chapters/chapter-2 + +**下一章预告**:数组与切片的区别、映射的底层原理、结构体嵌入与组合 diff --git a/chapters/chapter-2/go.mod b/chapters/chapter-2/go.mod new file mode 100644 index 0000000..9ff1861 --- /dev/null +++ b/chapters/chapter-2/go.mod @@ -0,0 +1,3 @@ +module go-tutorial + +go 1.21 diff --git a/chapters/chapter-2/main.go b/chapters/chapter-2/main.go new file mode 100644 index 0000000..fa565c1 --- /dev/null +++ b/chapters/chapter-2/main.go @@ -0,0 +1,241 @@ +package main + +import ( + "fmt" + "math" + "strings" +) + +// 2.1 变量声明示例 +func variableDeclaration() { + fmt.Println("=== 变量声明示例 ===") + + // 1. 显式类型 + var name string = "Alice" + var age int = 25 + fmt.Printf("name: %s, age: %d\n", name, age) + + // 2. 类型推断 + var city = "Beijing" + var score = 95.5 + fmt.Printf("city: %s, score: %.1f\n", city, score) + + // 3. 短声明 + x, y, z := 1, 2, 3 + fmt.Printf("x: %d, y: %d, z: %d\n", x, y, z) + + // 4. 多变量声明 + var ( + pi = 3.14159 + euler = 2.71828 + golden = 1.61803 + ) + fmt.Printf("pi: %.5f, e: %.5f, golden: %.5f\n", pi, euler, golden) +} + +// 2.2 零值示例 +func zeroValues() { + fmt.Println("\n=== 零值示例 ===") + + var intVar int + var floatVar float64 + var boolVar bool + var stringVar string + var ptrVar *int + + fmt.Printf("int: %d\n", intVar) + fmt.Printf("float: %f\n", floatVar) + fmt.Printf("bool: %v\n", boolVar) + fmt.Printf("string: '%s'\n", stringVar) + fmt.Printf("ptr: %v\n", ptrVar) + + // 结构体零值 + type User struct { + Name string + Age int + Email string + } + u := User{} + fmt.Printf("User: %+v\n", u) +} + +// 2.3 数据类型示例 +func dataTypes() { + fmt.Println("\n=== 数据类型示例 ===") + + // 整型 + var i8 int8 = 127 + var i64 int64 = 9223372036854775807 + fmt.Printf("int8: %d, int64: %d\n", i8, i64) + + // byte 和 rune + var b byte = 'A' + var r rune = '中' + fmt.Printf("byte: %c (%d), rune: %c (%d)\n", b, b, r, r) + + // 浮点数精度问题 + a := 0.1 + 0.2 + b := 0.3 + fmt.Printf("0.1 + 0.2 == 0.3: %v\n", a == b) + fmt.Printf("0.1 + 0.2 = %.20f\n", a) + + // 字符串 + s := "Hello 世界" + fmt.Printf("字符串: %s\n", s) + fmt.Printf("字节数: %d\n", len(s)) + + // 遍历字符串 + fmt.Print("字符遍历: ") + for i, r := range s { + fmt.Printf("[%d]%c ", i, r) + } + fmt.Println() +} + +// 2.4 类型转换示例 +func typeConversion() { + fmt.Println("\n=== 类型转换示例 ===") + + var f float64 = 3.14159 + var i int = int(f) // 截断 + fmt.Printf("float64(3.14159) -> int: %d\n", i) + + // 四舍五入 + i = int(math.Round(f)) + fmt.Printf("round(3.14159): %d\n", i) + + // 字符串转数字 + numStr := "42" + num, _ := strconv.Atoi(numStr) + fmt.Printf("字符串 '%s' -> 数字: %d\n", numStr, num) +} + +// 2.5 运算符示例 +func operators() { + fmt.Println("\n=== 运算符示例 ===") + + a, b := 10, 3 + + // 算术运算 + fmt.Printf("%d + %d = %d\n", a, b, a+b) + fmt.Printf("%d / %d = %d (整数除法)\n", a, b, a/b) + fmt.Printf("%d / %d = %.2f (浮点除法)\n", a, b, float64(a)/float64(b)) + + // 位运算 + x, y := 6, 3 // 110, 011 + fmt.Printf("%d & %d = %d\n", x, y, x&y) + fmt.Printf("%d | %d = %d\n", x, y, x|y) + fmt.Printf("%d ^ %d = %d\n", x, y, x^y) + fmt.Printf("%d << 1 = %d\n", x, x<<1) +} + +// 2.6 流程控制示例 +func flowControl() { + fmt.Println("\n=== 流程控制示例 ===") + + // if-else + score := 85 + if score >= 90 { + fmt.Println("优秀") + } else if score >= 80 { + fmt.Println("良好") + } else { + fmt.Println("及格") + } + + // switch + day := 3 + switch day { + case 1, 2, 3, 4, 5: + fmt.Println("工作日") + case 6, 7: + fmt.Println("周末") + default: + fmt.Println("无效日期") + } + + // for 循环 + fmt.Print("for 循环: ") + for i := 0; i < 5; i++ { + fmt.Printf("%d ", i) + } + fmt.Println() + + // range 遍历 + slice := []int{10, 20, 30, 40, 50} + fmt.Print("range 遍历: ") + for i, v := range slice { + fmt.Printf("[%d]=%d ", i, v) + } + fmt.Println() +} + +// 2.7 综合案例:计算器 +func calculator() { + fmt.Println("\n=== 简易计算器 ===") + + num1 := 10.5 + num2 := 3.2 + operators := []string{"+", "-", "*", "/"} + + for _, op := range operators { + var result float64 + switch op { + case "+": + result = num1 + num2 + case "-": + result = num1 - num2 + case "*": + result = num1 * num2 + case "/": + result = num1 / num2 + } + fmt.Printf("%.1f %s %.1f = %.2f\n", num1, op, num2, result) + } +} + +// 2.7 综合案例:素数判断 +func primeNumbers() { + fmt.Println("\n=== 素数统计 ===") + + count := 0 + for i := 2; i <= 100; i++ { + if isPrime(i) { + fmt.Printf("%d ", i) + count++ + if count%10 == 0 { + fmt.Println() + } + } + } + fmt.Printf("\n1-100 共有 %d 个素数\n", count) +} + +func isPrime(n int) bool { + if n <= 1 { + return false + } + if n == 2 { + return true + } + if n%2 == 0 { + return false + } + for i := 3; i*i <= n; i += 2 { + if n%i == 0 { + return false + } + } + return true +} + +func main() { + variableDeclaration() + zeroValues() + dataTypes() + typeConversion() + operators() + flowControl() + calculator() + primeNumbers() +}