Update
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func exercise1() func(int) int {
|
||||
fmt.Println("=== 练习1:基础闭包 ===")
|
||||
|
||||
// 创建一个闭包函数,它捕获外部变量multiplier
|
||||
// 该闭包接收一个int参数并返回乘以multiplier的结果
|
||||
|
||||
multiplier := 3
|
||||
____ := func(num int) ____ {
|
||||
return ____
|
||||
}
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise2() func() int {
|
||||
fmt.Println("=== 练习2:闭包状态保持 ===")
|
||||
|
||||
// 创建一个递增计数器闭包
|
||||
// 每次调用返回的函数时,计数器加1
|
||||
// 提示:使用匿名函数捕获外部变量
|
||||
|
||||
count := ____
|
||||
|
||||
____ := func() ____ {
|
||||
____
|
||||
return ____
|
||||
}
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise3() func() int {
|
||||
fmt.Println("=== 练习3:斐波那契数列闭包 ===")
|
||||
|
||||
// 创建一个生成斐波那契数列的闭包
|
||||
// 每次调用返回下一个斐波那契数
|
||||
// 数列: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34...
|
||||
|
||||
a, b := ____, ____
|
||||
|
||||
____ := func() ____ {
|
||||
result := ____
|
||||
a, b = ____
|
||||
return ____
|
||||
}
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise4() func(int) bool {
|
||||
fmt.Println("=== 练习4:闭包配置 ===")
|
||||
|
||||
// 创建一个检查数字是否在范围内的闭包生成器
|
||||
// 该生成器接受min和max两个参数,返回一个检查函数
|
||||
// 检查函数判断输入数字是否在[min, max]范围内
|
||||
|
||||
min := 10
|
||||
max := ____
|
||||
|
||||
____ := func(num int) ____ {
|
||||
return num >= ____ && num <= ____
|
||||
}
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise5(start int) func(int) int {
|
||||
fmt.Println("=== 练习5:闭包累加器 ===")
|
||||
|
||||
// 创建一个累加器闭包
|
||||
// 从start开始,每次调用累加参数值
|
||||
// 提示:闭包应该能访问外部作用域的变量
|
||||
|
||||
total := ____
|
||||
|
||||
____ := func(n int) ____ {
|
||||
____
|
||||
return ____
|
||||
}
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== 闭包 练习 ===\n")
|
||||
|
||||
add3 := exercise1()
|
||||
fmt.Printf("练习1结果: add3(4) = %d\n", add3(4))
|
||||
fmt.Printf("练习1结果: add3(5) = %d\n", add3(5))
|
||||
|
||||
counter := exercise2()
|
||||
fmt.Printf("练习2结果: counter() = %d\n", counter())
|
||||
fmt.Printf("练习2结果: counter() = %d\n", counter())
|
||||
fmt.Printf("练习2结果: counter() = %d\n", counter())
|
||||
|
||||
fib := exercise3()
|
||||
fmt.Printf("练习3结果: fib() = %d\n", fib())
|
||||
fmt.Printf("练习3结果: fib() = %d\n", fib())
|
||||
fmt.Printf("练习3结果: fib() = %d\n", fib())
|
||||
fmt.Printf("练习3结果: fib() = %d\n", fib())
|
||||
fmt.Printf("练习3结果: fib() = %d\n", fib())
|
||||
|
||||
inRange := exercise4()
|
||||
fmt.Printf("练习4结果: inRange(15) = %t\n", inRange(15))
|
||||
fmt.Printf("练习4结果: inRange(5) = %t\n", inRange(5))
|
||||
fmt.Printf("练习4结果: inRange(20) = %t\n", inRange(20))
|
||||
|
||||
accumulator := exercise5(100)
|
||||
fmt.Printf("练习5结果: accumulator(10) = %d\n", accumulator(10))
|
||||
fmt.Printf("练习5结果: accumulator(20) = %d\n", accumulator(20))
|
||||
fmt.Printf("练习5结果: accumulator(30) = %d\n", accumulator(30))
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func captureOutput(f func()) string {
|
||||
old := os.Stdout
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stdout = w
|
||||
|
||||
f()
|
||||
|
||||
w.Close()
|
||||
os.Stdout = old
|
||||
|
||||
var buf bytes.Buffer
|
||||
buf.ReadFrom(r)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func TestExercise1(t *testing.T) {
|
||||
add3 := exercise1()
|
||||
result1 := add3(4)
|
||||
if result1 != 12 {
|
||||
t.Errorf("期望 12, 实际: %d", result1)
|
||||
}
|
||||
result2 := add3(5)
|
||||
if result2 != 15 {
|
||||
t.Errorf("期望 15, 实际: %d", result2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise2(t *testing.T) {
|
||||
counter := exercise2()
|
||||
result1 := counter()
|
||||
if result1 != 1 {
|
||||
t.Errorf("期望 1, 实际: %d", result1)
|
||||
}
|
||||
result2 := counter()
|
||||
if result2 != 2 {
|
||||
t.Errorf("期望 2, 实际: %d", result2)
|
||||
}
|
||||
result3 := counter()
|
||||
if result3 != 3 {
|
||||
t.Errorf("期望 3, 实际: %d", result3)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise3(t *testing.T) {
|
||||
fib := exercise3()
|
||||
expected := []int{0, 1, 1, 2, 3}
|
||||
for i, exp := range expected {
|
||||
result := fib()
|
||||
if result != exp {
|
||||
t.Errorf("第%d个斐波那契数期望 %d, 实际: %d", i+1, exp, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise4(t *testing.T) {
|
||||
inRange := exercise4()
|
||||
if !inRange(15) {
|
||||
t.Errorf("15应该在范围内")
|
||||
}
|
||||
if inRange(5) {
|
||||
t.Errorf("5不应该在范围内")
|
||||
}
|
||||
if !inRange(20) {
|
||||
t.Errorf("20应该在范围内")
|
||||
}
|
||||
if inRange(21) {
|
||||
t.Errorf("21不应该在范围内")
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise5(t *testing.T) {
|
||||
accumulator := exercise5(100)
|
||||
result1 := accumulator(10)
|
||||
if result1 != 110 {
|
||||
t.Errorf("期望 110, 实际: %d", result1)
|
||||
}
|
||||
result2 := accumulator(20)
|
||||
if result2 != 130 {
|
||||
t.Errorf("期望 130, 实际: %d", result2)
|
||||
}
|
||||
result3 := accumulator(30)
|
||||
if result3 != 160 {
|
||||
t.Errorf("期望 160, 实际: %d", result3)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMainFunction(t *testing.T) {
|
||||
output := captureOutput(main)
|
||||
|
||||
requiredSections := []string{
|
||||
"=== 闭包 练习 ===",
|
||||
"练习1:基础闭包",
|
||||
"练习2:闭包状态保持",
|
||||
"练习3:斐波那契数列闭包",
|
||||
"练习4:闭包配置",
|
||||
"练习5:闭包累加器",
|
||||
}
|
||||
|
||||
for _, section := range requiredSections {
|
||||
if !strings.Contains(output, section) {
|
||||
t.Errorf("期望输出包含 '%s'", section)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func exercise1(apply func(int) int, value int) int {
|
||||
fmt.Println("=== 练习1:函数作为参数 ===")
|
||||
|
||||
// 接收一个函数apply和一个值value
|
||||
// 调用apply函数处理value并返回结果
|
||||
|
||||
result := ____
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise2() func(int) int {
|
||||
fmt.Println("=== 练习2:函数作为返回值 ===")
|
||||
|
||||
// 返回一个函数,该函数将输入值乘以2
|
||||
// 提示:返回一个匿名函数
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise3(vals []int, filter func(int) bool) []int {
|
||||
fmt.Println("=== 练习3:过滤器函数 ===")
|
||||
|
||||
// 接收一个int切片和一个过滤函数
|
||||
// 返回过滤后的切片(只保留满足条件的元素)
|
||||
|
||||
var result ____
|
||||
|
||||
for _, val := range ____ {
|
||||
if ____(val) {
|
||||
result = append(result, ____)
|
||||
}
|
||||
}
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise4(vals []int, mapper func(int) int) []int {
|
||||
fmt.Println("=== 练习4:映射函数 ===")
|
||||
|
||||
// 接收一个int切片和一个映射函数
|
||||
// 返回映射后的切片(每个元素都经过mapper函数处理)
|
||||
|
||||
result := make([]int, ____)
|
||||
|
||||
for i, val := range ____ {
|
||||
result[i] = ____(val)
|
||||
}
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise5(vals []int, reducer func(int, int) int, initial int) int {
|
||||
fmt.Println("=== 练习5:归约函数 ===")
|
||||
|
||||
// 接收一个int切片、一个归约函数和初始值
|
||||
// 返回归约结果
|
||||
// 例如:对切片求和、求积等
|
||||
|
||||
result := ____
|
||||
|
||||
for _, val := range ____ {
|
||||
result = ____(result, val)
|
||||
}
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise6() int {
|
||||
fmt.Println("=== 练习6:函数组合 ===")
|
||||
|
||||
// 组合两个函数
|
||||
// square函数:计算平方
|
||||
// double函数:计算双倍
|
||||
// 返回 double(square(3)) 的结果
|
||||
// 即:先平方(9),再双倍(18)
|
||||
|
||||
square := func(n int) int { return ____ }
|
||||
double := func(n int) int { return ____ }
|
||||
|
||||
compose := func(f, g func(int) int, x int) int {
|
||||
return ____(____(x))
|
||||
}
|
||||
|
||||
return compose(____, ____, 3)
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== 高阶函数 练习 ===\n")
|
||||
|
||||
平方 := func(n int) int { return n * n }
|
||||
result1 := exercise1(平方, 4)
|
||||
fmt.Printf("练习1结果: %d\n", result1)
|
||||
|
||||
double := exercise2()
|
||||
result2 := double(5)
|
||||
fmt.Printf("练习2结果: %d\n", result2)
|
||||
|
||||
nums1 := []int{1, 2, 3, 4, 5, 6}
|
||||
isEven := func(n int) bool { return n%2 == 0 }
|
||||
result3 := exercise3(nums1, isEven)
|
||||
fmt.Printf("练习3结果: %v\n", result3)
|
||||
|
||||
nums2 := []int{1, 2, 3, 4, 5}
|
||||
multiplyBy3 := func(n int) int { return n * 3 }
|
||||
result4 := exercise4(nums2, multiplyBy3)
|
||||
fmt.Printf("练习4结果: %v\n", result4)
|
||||
|
||||
nums3 := []int{1, 2, 3, 4, 5}
|
||||
sum := func(acc, val int) int { return acc + val }
|
||||
result5 := exercise5(nums3, sum, 0)
|
||||
fmt.Printf("练习5结果: %d\n", result5)
|
||||
|
||||
result6 := exercise6()
|
||||
fmt.Printf("练习6结果: %d\n", result6)
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func captureOutput(f func()) string {
|
||||
old := os.Stdout
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stdout = w
|
||||
|
||||
f()
|
||||
|
||||
w.Close()
|
||||
os.Stdout = old
|
||||
|
||||
var buf bytes.Buffer
|
||||
buf.ReadFrom(r)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func TestExercise1(t *testing.T) {
|
||||
square := func(n int) int { return n * n }
|
||||
result := exercise1(square, 4)
|
||||
if result != 16 {
|
||||
t.Errorf("期望 16, 实际: %d", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise2(t *testing.T) {
|
||||
double := exercise2()
|
||||
result := double(5)
|
||||
if result != 10 {
|
||||
t.Errorf("期望 10, 实际: %d", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise3(t *testing.T) {
|
||||
nums := []int{1, 2, 3, 4, 5, 6}
|
||||
isEven := func(n int) bool { return n%2 == 0 }
|
||||
result := exercise3(nums, isEven)
|
||||
|
||||
if len(result) != 3 {
|
||||
t.Errorf("期望长度 3, 实际: %d", len(result))
|
||||
}
|
||||
|
||||
expected := []int{2, 4, 6}
|
||||
for i, val := range expected {
|
||||
if result[i] != val {
|
||||
t.Errorf("索引 %d 期望 %d, 实际: %d", i, val, result[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise4(t *testing.T) {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
multiplyBy3 := func(n int) int { return n * 3 }
|
||||
result := exercise4(nums, multiplyBy3)
|
||||
|
||||
if len(result) != 5 {
|
||||
t.Errorf("期望长度 5, 实际: %d", len(result))
|
||||
}
|
||||
|
||||
expected := []int{3, 6, 9, 12, 15}
|
||||
for i, val := range expected {
|
||||
if result[i] != val {
|
||||
t.Errorf("索引 %d 期望 %d, 实际: %d", i, val, result[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise5(t *testing.T) {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
sum := func(acc, val int) int { return acc + val }
|
||||
result := exercise5(nums, sum, 0)
|
||||
|
||||
if result != 15 {
|
||||
t.Errorf("期望 15, 实际: %d", result)
|
||||
}
|
||||
|
||||
product := func(acc, val int) int { return acc * val }
|
||||
result = exercise5(nums, product, 1)
|
||||
|
||||
if result != 120 {
|
||||
t.Errorf("期望 120, 实际: %d", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise6(t *testing.T) {
|
||||
result := exercise6()
|
||||
if result != 18 {
|
||||
t.Errorf("期望 18, 实际: %d", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMainFunction(t *testing.T) {
|
||||
output := captureOutput(main)
|
||||
|
||||
requiredSections := []string{
|
||||
"=== 高阶函数 练习 ===",
|
||||
"练习1:函数作为参数",
|
||||
"练习2:函数作为返回值",
|
||||
"练习3:过滤器函数",
|
||||
"练习4:映射函数",
|
||||
"练习5:归约函数",
|
||||
"练习6:函数组合",
|
||||
}
|
||||
|
||||
for _, section := range requiredSections {
|
||||
if !strings.Contains(output, section) {
|
||||
t.Errorf("期望输出包含 '%s'", section)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
# 01-arrays - 数组
|
||||
|
||||
## 知识点讲解
|
||||
|
||||
### 数组定义
|
||||
|
||||
```go
|
||||
var arr1 [5]int // 声明一个长度为5的int数组
|
||||
var arr2 = [5]int{1, 2, 3, 4, 5} // 声明并初始化
|
||||
arr3 := [5]int{1, 2, 3} // 部分初始化,其余为0
|
||||
arr4 := [...]int{1, 2, 3, 4, 5} // 让编译器推断长度
|
||||
```
|
||||
|
||||
### 访问和修改
|
||||
|
||||
```go
|
||||
arr := [3]int{10, 20, 30}
|
||||
fmt.Println(arr[0]) // 输出: 10
|
||||
arr[1] = 100 // 修改元素
|
||||
```
|
||||
|
||||
### 数组特点
|
||||
|
||||
- **固定长度**:创建后长度不可变
|
||||
- **值类型**:数组赋值会拷贝整个数组
|
||||
- **相同类型**:必须指定长度和元素类型
|
||||
- **内存连续**:元素在内存中连续存储
|
||||
|
||||
### 重要提示
|
||||
|
||||
- Go中数组长度是类型的一部分,`[3]int` 和 `[4]int` 是不同的类型
|
||||
- 数组作为参数传递时会拷贝整个数组,而不是引用
|
||||
|
||||
## 学习目标
|
||||
|
||||
完成本练习后,你将:
|
||||
- ✅ 掌握数组的声明和初始化
|
||||
- ✅ 学会数组的访问和修改
|
||||
- ✅ 理解数组的值类型特性
|
||||
- ✅ 了解数组的遍历方式
|
||||
|
||||
## 练习说明
|
||||
|
||||
打开 `main.go`,根据注释提示填充代码,完成后运行 `go test -v` 验证答案。
|
||||
@@ -0,0 +1,95 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func exercise1() [5]int {
|
||||
fmt.Println("=== 练习1:数组声明与初始化 ===")
|
||||
|
||||
// 声明一个长度为5的int数组
|
||||
// 初始化所有元素为10
|
||||
var arr ____
|
||||
|
||||
for i := 0; i < ____(arr); i++ {
|
||||
arr[i] = ____
|
||||
}
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise2() string {
|
||||
fmt.Println("=== 练习2:数组访问与修改 ===")
|
||||
|
||||
// 修改数组元素并返回修改后的字符串表示
|
||||
fruits := [4]string{"苹果", "香蕉", "橙子", "葡萄"}
|
||||
|
||||
fruits[____] = "芒果"
|
||||
|
||||
fmt.Printf("修改后的水果: %s\n", fruits)
|
||||
|
||||
return "芒果"
|
||||
}
|
||||
|
||||
func exercise3() int {
|
||||
fmt.Println("=== 练习3:数组求和 ===")
|
||||
|
||||
// 计算数组所有元素的和
|
||||
numbers := [5]int{10, 20, 30, 40, 50}
|
||||
|
||||
sum := ____
|
||||
|
||||
for i := 0; i < ____(numbers); i++ {
|
||||
sum += ____
|
||||
}
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise4() [3]int {
|
||||
fmt.Println("=== 练习4:数组拷贝 ===")
|
||||
|
||||
// 创建一个数组并拷贝到另一个数组
|
||||
// 修改原数组,观察拷贝的数组是否变化
|
||||
arr1 := [3]int{1, 2, 3}
|
||||
|
||||
arr2 := ____
|
||||
|
||||
arr1[0] = 99
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise5() int {
|
||||
fmt.Println("=== 练习5:二维数组 ===")
|
||||
|
||||
// 计算二维数组的和
|
||||
matrix := [3][2]int{{1, 2}, {3, 4}, {5, 6}}
|
||||
|
||||
sum := ____
|
||||
|
||||
for i := 0; i < ____(matrix); i++ {
|
||||
for j := 0; j < ____(matrix[i]); j++ {
|
||||
sum += ____
|
||||
}
|
||||
}
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== 数组 练习 ===\n")
|
||||
|
||||
result1 := exercise1()
|
||||
fmt.Printf("练习1结果: %v\n", result1)
|
||||
|
||||
result2 := exercise2()
|
||||
fmt.Printf("练习2结果: %s\n", result2)
|
||||
|
||||
result3 := exercise3()
|
||||
fmt.Printf("练习3结果: %d\n", result3)
|
||||
|
||||
result4 := exercise4()
|
||||
fmt.Printf("练习4结果: %v\n", result4)
|
||||
|
||||
result5 := exercise5()
|
||||
fmt.Printf("练习5结果: %d\n", result5)
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func captureOutput(f func()) string {
|
||||
old := os.Stdout
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stdout = w
|
||||
|
||||
f()
|
||||
|
||||
w.Close()
|
||||
os.Stdout = old
|
||||
|
||||
var buf bytes.Buffer
|
||||
buf.ReadFrom(r)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func TestExercise1(t *testing.T) {
|
||||
result := exercise1()
|
||||
expected := [5]int{10, 10, 10, 10, 10}
|
||||
if result != expected {
|
||||
t.Errorf("期望 %v, 实际: %v", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise2(t *testing.T) {
|
||||
result := exercise2()
|
||||
if result != "芒果" {
|
||||
t.Errorf("期望 '芒果', 实际: %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise3(t *testing.T) {
|
||||
result := exercise3()
|
||||
if result != 150 {
|
||||
t.Errorf("期望 150, 实际: %d", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise4(t *testing.T) {
|
||||
result := exercise4()
|
||||
expected := [3]int{1, 2, 3}
|
||||
if result != expected {
|
||||
t.Errorf("期望 %v, 实际: %v", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise5(t *testing.T) {
|
||||
result := exercise5()
|
||||
if result != 21 {
|
||||
t.Errorf("期望 21, 实际: %d", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMainFunction(t *testing.T) {
|
||||
output := captureOutput(main)
|
||||
|
||||
requiredSections := []string{
|
||||
"=== 数组 练习 ===",
|
||||
"练习1:数组声明与初始化",
|
||||
"练习2:数组访问与修改",
|
||||
"练习3:数组求和",
|
||||
"练习4:数组拷贝",
|
||||
"练习5:二维数组",
|
||||
}
|
||||
|
||||
for _, section := range requiredSections {
|
||||
if !strings.Contains(output, section) {
|
||||
t.Errorf("期望输出包含 '%s'", section)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
# 02-slices - 切片操作
|
||||
|
||||
## 知识点讲解
|
||||
|
||||
### 切片定义
|
||||
|
||||
```go
|
||||
var s1 []int // 声明一个切片(nil切片)
|
||||
s2 := []int{1, 2, 3, 4, 5} // 声明并初始化
|
||||
s3 := make([]int, 5) // 创建长度为5的切片
|
||||
s4 := make([]int, 5, 10) // 创建长度为5,容量为10的切片
|
||||
```
|
||||
|
||||
### 从数组或切片创建
|
||||
|
||||
```go
|
||||
arr := [5]int{1, 2, 3, 4, 5}
|
||||
s1 := arr[1:3] // [2, 3]
|
||||
s2 := arr[:3] // [1, 2, 3]
|
||||
s3 := arr[2:] // [3, 4, 5]
|
||||
```
|
||||
|
||||
### 添加元素
|
||||
|
||||
```go
|
||||
s := []int{1, 2, 3}
|
||||
s = append(s, 4) // [1, 2, 3, 4]
|
||||
s = append(s, 5, 6) // [1, 2, 3, 4, 5, 6]
|
||||
```
|
||||
|
||||
### 切片特性
|
||||
|
||||
- **动态长度**:可以自动扩容
|
||||
- **引用类型**:切片指向底层数组
|
||||
- **三个属性**:指针、长度、容量
|
||||
- **浅拷贝**:切片赋值共享底层数组
|
||||
|
||||
### 重要提示
|
||||
|
||||
- 使用 `append` 时如果超出容量会创建新数组
|
||||
- 切片切片操作不会复制元素,只是创建新的视图
|
||||
|
||||
## 学习目标
|
||||
|
||||
完成本练习后,你将:
|
||||
- ✅ 掌握切片的声明和创建
|
||||
- ✅ 学会使用 append 添加元素
|
||||
- ✅ 理解切片的动态扩容
|
||||
- ✅ 了解切片的底层结构
|
||||
|
||||
## 练习说明
|
||||
|
||||
打开 `main.go`,根据注释提示填充代码,完成后运行 `go test -v` 验证答案。
|
||||
@@ -0,0 +1,96 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func exercise1() []int {
|
||||
fmt.Println("=== 练习1:切片声明与初始化 ===")
|
||||
|
||||
// 创建一个长度为3的int切片,初始值为[1, 2, 3]
|
||||
s := make([]int, ____)
|
||||
s[0], s[1], s[2] = ____, ____, ____
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise2() int {
|
||||
fmt.Println("=== 练习2:切片追加 ===")
|
||||
|
||||
// 向切片中添加元素并返回新长度
|
||||
fruits := []string{"苹果", "香蕉"}
|
||||
fruits = append(fruits, ____)
|
||||
fruits = append(fruits, ____, ____)
|
||||
|
||||
return ____(fruits)
|
||||
}
|
||||
|
||||
func exercise3() []int {
|
||||
fmt.Println("=== 练习3:切片切片 ===")
|
||||
|
||||
// 从切片中提取子切片
|
||||
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
|
||||
// 提取索引2到6(不包含6)
|
||||
sub1 := numbers[____:____]
|
||||
|
||||
// 提取前5个元素
|
||||
sub2 := numbers[:____]
|
||||
|
||||
// 提取从第5个开始到末尾
|
||||
sub3 := numbers[____:]
|
||||
|
||||
fmt.Printf("子切片1: %v\n", sub1)
|
||||
fmt.Printf("子切片2: %v\n", sub2)
|
||||
fmt.Printf("子切片3: %v\n", sub3)
|
||||
|
||||
return sub1
|
||||
}
|
||||
|
||||
func exercise4() int {
|
||||
fmt.Println("=== 练习4:切片拷贝 ===")
|
||||
|
||||
// 修改原始切片,观察使用copy复制的切片是否受影响
|
||||
s1 := []int{1, 2, 3}
|
||||
s2 := make([]int, ____(s1))
|
||||
|
||||
copy(____, s1)
|
||||
|
||||
s1[0] = 99
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise5() []int {
|
||||
fmt.Println("=== 练习5:切片遍历 ===")
|
||||
|
||||
// 创建一个新切片,包含原切片中所有偶数
|
||||
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
|
||||
var evens ____
|
||||
|
||||
for _, num := range ____ {
|
||||
if num%2 == ____ {
|
||||
evens = append(____, num)
|
||||
}
|
||||
}
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== 切片 练习 ===\n")
|
||||
|
||||
result1 := exercise1()
|
||||
fmt.Printf("练习1结果: %v\n", result1)
|
||||
|
||||
result2 := exercise2()
|
||||
fmt.Printf("练习2结果: %d\n", result2)
|
||||
|
||||
result3 := exercise3()
|
||||
fmt.Printf("练习3结果: %v\n", result3)
|
||||
|
||||
result4 := exercise4()
|
||||
fmt.Printf("练习4结果: %d\n", result4)
|
||||
|
||||
result5 := exercise5()
|
||||
fmt.Printf("练习5结果: %v\n", result5)
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func captureOutput(f func()) string {
|
||||
old := os.Stdout
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stdout = w
|
||||
|
||||
f()
|
||||
|
||||
w.Close()
|
||||
os.Stdout = old
|
||||
|
||||
var buf bytes.Buffer
|
||||
buf.ReadFrom(r)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func TestExercise1(t *testing.T) {
|
||||
result := exercise1()
|
||||
expected := []int{1, 2, 3}
|
||||
if len(result) != len(expected) {
|
||||
t.Errorf("期望长度 %d, 实际: %d", len(expected), len(result))
|
||||
}
|
||||
for i, v := range expected {
|
||||
if result[i] != v {
|
||||
t.Errorf("索引 %d 期望 %d, 实际: %d", i, v, result[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise2(t *testing.T) {
|
||||
result := exercise2()
|
||||
if result != 5 {
|
||||
t.Errorf("期望长度 5, 实际: %d", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise3(t *testing.T) {
|
||||
result := exercise3()
|
||||
expected := []int{3, 4, 5}
|
||||
if len(result) != len(expected) {
|
||||
t.Errorf("期望长度 %d, 实际: %d", len(expected), len(result))
|
||||
}
|
||||
for i, v := range expected {
|
||||
if result[i] != v {
|
||||
t.Errorf("索引 %d 期望 %d, 实际: %d", i, v, result[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise4(t *testing.T) {
|
||||
result := exercise4()
|
||||
if result != 1 {
|
||||
t.Errorf("期望 1, 实际: %d", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise5(t *testing.T) {
|
||||
result := exercise5()
|
||||
expected := []int{2, 4, 6, 8, 10}
|
||||
if len(result) != len(expected) {
|
||||
t.Errorf("期望长度 %d, 实际: %d", len(expected), len(result))
|
||||
}
|
||||
for i, v := range expected {
|
||||
if result[i] != v {
|
||||
t.Errorf("索引 %d 期望 %d, 实际: %d", i, v, result[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMainFunction(t *testing.T) {
|
||||
output := captureOutput(main)
|
||||
|
||||
requiredSections := []string{
|
||||
"=== 切片 练习 ===",
|
||||
"练习1:切片声明与初始化",
|
||||
"练习2:切片追加",
|
||||
"练习3:切片切片",
|
||||
"练习4:切片拷贝",
|
||||
"练习5:切片遍历",
|
||||
}
|
||||
|
||||
for _, section := range requiredSections {
|
||||
if !strings.Contains(output, section) {
|
||||
t.Errorf("期望输出包含 '%s'", section)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
# 03-maps - map使用
|
||||
|
||||
## 知识点讲解
|
||||
|
||||
### map定义
|
||||
|
||||
```go
|
||||
var m1 map[string]int // 声明一个map(nil map)
|
||||
m2 := map[string]int{} // 声明并初始化空map
|
||||
m3 := map[string]int{ // 声明并初始化
|
||||
"张三": 90,
|
||||
"李四": 85,
|
||||
}
|
||||
m4 := make(map[string]int) // 创建一个空map
|
||||
```
|
||||
|
||||
### 添加和修改
|
||||
|
||||
```go
|
||||
m := make(map[string]int)
|
||||
m["key"] = 100 // 添加元素
|
||||
m["key"] = 200 // 修改元素
|
||||
```
|
||||
|
||||
### 读取和删除
|
||||
|
||||
```go
|
||||
m := map[string]int{"a": 1, "b": 2}
|
||||
value := m["a"] // 读取值
|
||||
value, exists := m["c"] // 读取值,检查是否存在
|
||||
delete(m, "b") // 删除元素
|
||||
```
|
||||
|
||||
### 遍历map
|
||||
|
||||
```go
|
||||
m := map[string]int{"a": 1, "b": 2, "c": 3}
|
||||
for key, value := range m { // 遍历map
|
||||
fmt.Printf("%s: %d\n", key, value)
|
||||
}
|
||||
```
|
||||
|
||||
### map特性
|
||||
|
||||
- **无序**:map中元素的顺序是不确定的
|
||||
- **引用类型**:map赋值共享底层数据结构
|
||||
- **零值**:未找到时对应类型的零值
|
||||
- **并发安全**:多个goroutine同时读写需要加锁
|
||||
|
||||
## 学习目标
|
||||
|
||||
完成本练习后,你将:
|
||||
- ✅ 掌握map的声明和初始化
|
||||
- ✅ 学会添加、修改、删除元素
|
||||
- ✅ 理解如何检查元素是否存在
|
||||
- ✅ 掌握map的遍历方式
|
||||
|
||||
## 练习说明
|
||||
|
||||
打开 `main.go`,根据注释提示填充代码,完成后运行 `go test -v` 验证答案。
|
||||
@@ -0,0 +1,112 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func exercise1() map[string]int {
|
||||
fmt.Println("=== 练习1:map声明与初始化 ===")
|
||||
|
||||
// 创建一个map,键为string类型,值为int类型
|
||||
// 添加"张三": 90, "李四": 85, "王五": 95
|
||||
scores := ____
|
||||
|
||||
scores["张三"] = ____
|
||||
scores["李四"] = ____
|
||||
scores["王五"] = ____
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise2() string {
|
||||
fmt.Println("=== 练习2:map读取与检查 ===")
|
||||
|
||||
// 读取map中的值并检查是否存在
|
||||
scores := map[string]int{
|
||||
"张三": 90,
|
||||
"李四": 85,
|
||||
}
|
||||
|
||||
score, exists := ____
|
||||
|
||||
if exists {
|
||||
fmt.Printf("李四的分数是: %d\n", score)
|
||||
}
|
||||
|
||||
return "85"
|
||||
}
|
||||
|
||||
func exercise3() int {
|
||||
fmt.Println("=== 练习3:map遍历 ===")
|
||||
|
||||
// 遍历map,计算所有分数的总和
|
||||
scores := map[string]int{
|
||||
"张三": 90,
|
||||
"李四": 85,
|
||||
"王五": 95,
|
||||
"赵六": 88,
|
||||
}
|
||||
|
||||
sum := ____
|
||||
|
||||
for ____, score := range ____ {
|
||||
sum += ____
|
||||
}
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise4() map[string]int {
|
||||
fmt.Println("=== 练习4:map删除元素 ===")
|
||||
|
||||
// 删除map中的元素并返回删除后的map
|
||||
scores := map[string]int{
|
||||
"张三": 90,
|
||||
"李四": 85,
|
||||
"王五": 95,
|
||||
}
|
||||
|
||||
____(scores, "李四")
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise5() []string {
|
||||
fmt.Println("=== 练习5:map筛选 ===")
|
||||
|
||||
// 筛选出分数大于等于90的学生姓名
|
||||
scores := map[string]int{
|
||||
"张三": 90,
|
||||
"李四": 85,
|
||||
"王五": 95,
|
||||
"赵六": 88,
|
||||
"钱七": 92,
|
||||
}
|
||||
|
||||
var topStudents ____
|
||||
|
||||
for name, score := range ____ {
|
||||
if score >= ____ {
|
||||
topStudents = append(____, ____)
|
||||
}
|
||||
}
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== map 练习 ===\n")
|
||||
|
||||
result1 := exercise1()
|
||||
fmt.Printf("练习1结果: %v\n", result1)
|
||||
|
||||
result2 := exercise2()
|
||||
fmt.Printf("练习2结果: %s\n", result2)
|
||||
|
||||
result3 := exercise3()
|
||||
fmt.Printf("练习3结果: %d\n", result3)
|
||||
|
||||
result4 := exercise4()
|
||||
fmt.Printf("练习4结果: %v\n", result4)
|
||||
|
||||
result5 := exercise5()
|
||||
fmt.Printf("练习5结果: %v\n", result5)
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func captureOutput(f func()) string {
|
||||
old := os.Stdout
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stdout = w
|
||||
|
||||
f()
|
||||
|
||||
w.Close()
|
||||
os.Stdout = old
|
||||
|
||||
var buf bytes.Buffer
|
||||
buf.ReadFrom(r)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func TestExercise1(t *testing.T) {
|
||||
result := exercise1()
|
||||
if result["张三"] != 90 || result["李四"] != 85 || result["王五"] != 95 {
|
||||
t.Errorf("期望值不正确: %v", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise2(t *testing.T) {
|
||||
result := exercise2()
|
||||
if result != "85" {
|
||||
t.Errorf("期望 '85', 实际: %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise3(t *testing.T) {
|
||||
result := exercise3()
|
||||
if result != 358 {
|
||||
t.Errorf("期望 358, 实际: %d", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise4(t *testing.T) {
|
||||
result := exercise4()
|
||||
if _, exists := result["李四"]; exists {
|
||||
t.Errorf("李四应该已被删除")
|
||||
}
|
||||
if result["张三"] != 90 {
|
||||
t.Errorf("张三的分数应该是 90")
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise5(t *testing.T) {
|
||||
result := exercise5()
|
||||
expectedCount := 3
|
||||
if len(result) != expectedCount {
|
||||
t.Errorf("期望数量 %d, 实际: %d", expectedCount, len(result))
|
||||
}
|
||||
|
||||
expectedNames := map[string]bool{"张三": false, "王五": false, "钱七": false}
|
||||
for _, name := range result {
|
||||
if _, found := expectedNames[name]; !found {
|
||||
t.Errorf("意外的学生名: %s", name)
|
||||
}
|
||||
expectedNames[name] = true
|
||||
}
|
||||
|
||||
for name, found := range expectedNames {
|
||||
if !found {
|
||||
t.Errorf("缺少学生名: %s", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMainFunction(t *testing.T) {
|
||||
output := captureOutput(main)
|
||||
|
||||
requiredSections := []string{
|
||||
"=== map 练习 ===",
|
||||
"练习1:map声明与初始化",
|
||||
"练习2:map读取与检查",
|
||||
"练习3:map遍历",
|
||||
"练习4:map删除元素",
|
||||
"练习5:map筛选",
|
||||
}
|
||||
|
||||
for _, section := range requiredSections {
|
||||
if !strings.Contains(output, section) {
|
||||
t.Errorf("期望输出包含 '%s'", section)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
# 04-structs - 结构体
|
||||
|
||||
## 知识点讲解
|
||||
|
||||
### 结构体定义
|
||||
|
||||
```go
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
Address string
|
||||
}
|
||||
```
|
||||
|
||||
### 创建结构体
|
||||
|
||||
```go
|
||||
// 方式1:按顺序赋值
|
||||
p1 := Person{"张三", 20, "北京"}
|
||||
|
||||
// 方式2:指定字段名(推荐)
|
||||
p2 := Person{
|
||||
Name: "李四",
|
||||
Age: 25,
|
||||
Address: "上海",
|
||||
}
|
||||
|
||||
// 方式3:使用new关键字,返回指针
|
||||
p3 := new(Person)
|
||||
p3.Name = "王五"
|
||||
p3.Age = 30
|
||||
```
|
||||
|
||||
### 结构体字段
|
||||
|
||||
```go
|
||||
p := Person{Name: "张三", Age: 20}
|
||||
p.Name = "李四" // 修改字段值
|
||||
fmt.Println(p.Age) // 访问字段值
|
||||
```
|
||||
|
||||
### 结构体方法
|
||||
|
||||
```go
|
||||
func (p Person) Introduce() string {
|
||||
return fmt.Sprintf("我是%s,今年%d岁", p.Name, p.Age)
|
||||
}
|
||||
```
|
||||
|
||||
### 匿名字段与嵌套
|
||||
|
||||
```go
|
||||
type Address struct {
|
||||
City string
|
||||
Country string
|
||||
}
|
||||
|
||||
type Person struct {
|
||||
Name string
|
||||
Address Address // 嵌套结构体
|
||||
}
|
||||
```
|
||||
|
||||
### 重要提示
|
||||
|
||||
- 结构体字段首字母大写表示公开,小写表示私有
|
||||
- 结构体作为函数参数时默认是值传递
|
||||
- 使用指针传递可以避免拷贝,提高性能
|
||||
|
||||
## 学习目标
|
||||
|
||||
完成本练习后,你将:
|
||||
- ✅ 掌握结构体的定义和创建
|
||||
- ✅ 学会访问和修改结构体字段
|
||||
- ✅ 理解结构体指针的使用
|
||||
- ✅ 掌握结构体的方法定义
|
||||
|
||||
## 练习说明
|
||||
|
||||
打开 `main.go`,根据注释提示填充代码,完成后运行 `go test -v` 验证答案。
|
||||
@@ -0,0 +1,111 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
Score float64
|
||||
}
|
||||
|
||||
func exercise1() Person {
|
||||
fmt.Println("=== 练习1:结构体定义与创建 ===")
|
||||
|
||||
// 创建一个Person结构体实例
|
||||
// 名字为"张三", 年龄为20, 分数为90.5
|
||||
|
||||
var p ____
|
||||
|
||||
p.Name = ____
|
||||
p.Age = ____
|
||||
p.Score = ____
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise2() Person {
|
||||
fmt.Println("=== 练习2:结构体字段修改 ===")
|
||||
|
||||
// 修改结构体字段并返回
|
||||
p := Person{Name: "李四", Age: 25, Score: 85.0}
|
||||
|
||||
p.____ = 26
|
||||
p.____ = 88.5
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
type Book struct {
|
||||
Title string
|
||||
Author string
|
||||
Price float64
|
||||
}
|
||||
|
||||
func (b Book) GetInfo() string {
|
||||
fmt.Println("=== 练习3:结构体方法 ===")
|
||||
|
||||
// 返回书籍的详细信息
|
||||
// 格式: "《书名》- 作者, 价格 ¥XX.XX"
|
||||
return fmt.Sprintf("《%s》-%s, 价格 ¥%.2f", ____, ____, ____)
|
||||
}
|
||||
|
||||
func exercise4() *Book {
|
||||
fmt.Println("=== 练习4:结构体指针 ===")
|
||||
|
||||
// 创建一个Book结构体指针
|
||||
// 使用new创建,并设置字段的值
|
||||
book := ____
|
||||
|
||||
book.Title = "Go语言圣经"
|
||||
book.____ = "Alan Donovan"
|
||||
book.____ = 99.0
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
type Student struct {
|
||||
Name string
|
||||
Grade int
|
||||
}
|
||||
|
||||
type Teacher struct {
|
||||
Name string
|
||||
Subject string
|
||||
}
|
||||
|
||||
func exercise5() interface{} {
|
||||
fmt.Println("=== 练习5:结构体数组 ===")
|
||||
|
||||
// 创建一个结构体切片
|
||||
// 包含2个学生和2个老师
|
||||
students := []Student{
|
||||
{Name: "张三", Grade: 1},
|
||||
{Name: ____, Grade: 2},
|
||||
}
|
||||
|
||||
teachers := []Teacher{
|
||||
{Name: "王老师", Subject: "数学"},
|
||||
{Name: ____, Subject: "英语"},
|
||||
}
|
||||
|
||||
return append(students, teachers...)
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== 结构体 练习 ===\n")
|
||||
|
||||
result1 := exercise1()
|
||||
fmt.Printf("练习1结果: %+v\n", result1)
|
||||
|
||||
result2 := exercise2()
|
||||
fmt.Printf("练习2结果: %+v\n", result2)
|
||||
|
||||
result3 := exercise3()
|
||||
fmt.Printf("练习3结果: %s\n", result3)
|
||||
|
||||
result4 := exercise4()
|
||||
fmt.Printf("练习4结果: %+v\n", *result4)
|
||||
|
||||
result5 := exercise5()
|
||||
fmt.Printf("练习5结果: %v (共%d个)\n", result5, len(result5.([]interface{})))
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func captureOutput(f func()) string {
|
||||
old := os.Stdout
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stdout = w
|
||||
|
||||
f()
|
||||
|
||||
w.Close()
|
||||
os.Stdout = old
|
||||
|
||||
var buf bytes.Buffer
|
||||
buf.ReadFrom(r)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func TestExercise1(t *testing.T) {
|
||||
result := exercise1()
|
||||
if result.Name != "张三" || result.Age != 20 || result.Score != 90.5 {
|
||||
t.Errorf("期望值不正确: %+v", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise2(t *testing.T) {
|
||||
result := exercise2()
|
||||
if result.Name != "李四" || result.Age != 26 || result.Score != 88.5 {
|
||||
t.Errorf("期望值不正确: %+v", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise3(t *testing.T) {
|
||||
book := Book{Title: "Go语言实战", Author: "William Kennedy", Price: 59.9}
|
||||
result := book.GetInfo()
|
||||
expected := "《Go语言实战》-William Kennedy, 价格 ¥59.90"
|
||||
if result != expected {
|
||||
t.Errorf("期望 '%s', 实际: '%s'", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise4(t *testing.T) {
|
||||
result := exercise4()
|
||||
if result.Title != "Go语言圣经" || result.Author != "Alan Donovan" || result.Price != 99.0 {
|
||||
t.Errorf("期望值不正确: %+v", *result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise5(t *testing.T) {
|
||||
result := exercise5()
|
||||
slice, ok := result.([]interface{})
|
||||
if !ok {
|
||||
t.Error("返回结果应该是切片")
|
||||
return
|
||||
}
|
||||
|
||||
if len(slice) != 4 {
|
||||
t.Errorf("期望4个元素, 实际: %d", len(slice))
|
||||
}
|
||||
}
|
||||
|
||||
func TestMainFunction(t *testing.T) {
|
||||
output := captureOutput(main)
|
||||
|
||||
requiredSections := []string{
|
||||
"=== 结构体 练习 ===",
|
||||
"练习1:结构体定义与创建",
|
||||
"练习2:结构体字段修改",
|
||||
"练习3:结构体方法",
|
||||
"练习4:结构体指针",
|
||||
"练习5:结构体数组",
|
||||
}
|
||||
|
||||
for _, section := range requiredSections {
|
||||
if !strings.Contains(output, section) {
|
||||
t.Errorf("期望输出包含 '%s'", section)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
# 01-pointers - 指针基础
|
||||
|
||||
## 知识点讲解
|
||||
|
||||
### 指针声明
|
||||
|
||||
```go
|
||||
var p *int // 声明一个int类型的指针
|
||||
x := 10
|
||||
p = &x // p是x的地址
|
||||
```
|
||||
|
||||
### 指针操作
|
||||
|
||||
```go
|
||||
x := 10
|
||||
p := &x // 取地址
|
||||
|
||||
fmt.Println(*p) // 解引用,输出10
|
||||
*p = 20 // 通过指针修改值
|
||||
fmt.Println(x) // 输出20
|
||||
```
|
||||
|
||||
### 指针与函数
|
||||
|
||||
```go
|
||||
function modifyValue(p *int) {
|
||||
*p = 100 // 修改指针指向的值
|
||||
}
|
||||
|
||||
x := 10
|
||||
modifyValue(&x) // 传递地址
|
||||
fmt.Println(x) // 输出100
|
||||
```
|
||||
|
||||
### 零值
|
||||
|
||||
```go
|
||||
var p *int // nil指针
|
||||
fmt.Println(p == nil) // true
|
||||
```
|
||||
|
||||
### 重要提示
|
||||
|
||||
- Go中有指针但没有指针运算
|
||||
- 指针可以用于共享数据、避免拷贝
|
||||
- 指针的零值是nil
|
||||
- 解引用nil指针会panic
|
||||
|
||||
## 学习目标
|
||||
|
||||
完成本练习后,你将:
|
||||
- ✅ 掌握指针的声明和创建
|
||||
- ✅ 学会取地址和解引用操作
|
||||
- ✅ 理解指针与函数参数的关系
|
||||
- ✅ 了解nil指针的概念
|
||||
|
||||
## 练习说明
|
||||
|
||||
打开 `main.go`,根据注释提示填充代码,完成后运行 `go test -v` 验证答案。
|
||||
@@ -0,0 +1,96 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func exercise1() int {
|
||||
fmt.Println("=== 练习1:指针声明 ===")
|
||||
|
||||
// 声明一个int变量和一个指向它的指针
|
||||
var x int = 10
|
||||
var p ____ // 声明指针类型
|
||||
|
||||
p = ____ // p指向x的地址
|
||||
|
||||
fmt.Printf("x的值: %d, x的地址: %p\n", x, p)
|
||||
fmt.Printf("*p的值: %d\n", ____)
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise2() int {
|
||||
fmt.Println("=== 练习2:指针解引用 ===")
|
||||
|
||||
// 通过指针修改值
|
||||
x := 20
|
||||
p := ____
|
||||
|
||||
____ = 30
|
||||
|
||||
fmt.Println("修改后x的值:", x)
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func modifyByPointer(p *int) {
|
||||
// 通过指针修改值
|
||||
____ = 100
|
||||
}
|
||||
|
||||
func exercise3() int {
|
||||
fmt.Println("=== 练习3:指针作为函数参数 ===")
|
||||
|
||||
// 使用指针作为函数参数
|
||||
x := 50
|
||||
|
||||
____(&x)
|
||||
|
||||
if x != 100 {
|
||||
fmt.Println("指针参数修改失败!")
|
||||
}
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise4() bool {
|
||||
fmt.Println("=== 练习4:指针零值 ===")
|
||||
|
||||
// 检查指针的零值
|
||||
var p ____
|
||||
|
||||
fmt.Printf("未初始化的指针: %v, 是否为nil: %t\n", p, ____)
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise5() int {
|
||||
fmt.Println("=== 练习5:指针与数组 ===")
|
||||
|
||||
// 使用指针访问数组元素
|
||||
arr := [5]int{10, 20, 30, 40, 50}
|
||||
|
||||
p := ____
|
||||
|
||||
fmt.Printf("第一个元素: %d\n", ____)
|
||||
fmt.Printf("第二个元素: %d\n", ____(p+1))
|
||||
|
||||
return arr[0]
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== 指针 练习 ===\n")
|
||||
|
||||
result1 := exercise1()
|
||||
fmt.Printf("练习1结果: %d\n", result1)
|
||||
|
||||
result2 := exercise2()
|
||||
fmt.Printf("练习2结果: %d\n", result2)
|
||||
|
||||
result3 := exercise3()
|
||||
fmt.Printf("练习3结果: %d\n", result3)
|
||||
|
||||
result4 := exercise4()
|
||||
fmt.Printf("练习4结果: %t\n", result4)
|
||||
|
||||
result5 := exercise5()
|
||||
fmt.Printf("练习5结果: %d\n", result5)
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func captureOutput(f func()) string {
|
||||
old := os.Stdout
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stdout = w
|
||||
|
||||
f()
|
||||
|
||||
w.Close()
|
||||
os.Stdout = old
|
||||
|
||||
var buf bytes.Buffer
|
||||
buf.ReadFrom(r)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func TestExercise1(t *testing.T) {
|
||||
result := exercise1()
|
||||
if result != 10 {
|
||||
t.Errorf("期望 10, 实际: %d", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise2(t *testing.T) {
|
||||
result := exercise2()
|
||||
if result != 30 {
|
||||
t.Errorf("期望 30, 实际: %d", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise3(t *testing.T) {
|
||||
result := exercise3()
|
||||
if result != 100 {
|
||||
t.Errorf("期望 100, 实际: %d", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise4(t *testing.T) {
|
||||
result := exercise4()
|
||||
if !result {
|
||||
t.Errorf("期望 true, 实际: %t", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise5(t *testing.T) {
|
||||
result := exercise5()
|
||||
if result != 10 {
|
||||
t.Errorf("期望 10, 实际: %d", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMainFunction(t *testing.T) {
|
||||
output := captureOutput(main)
|
||||
|
||||
requiredSections := []string{
|
||||
"=== 指针 练习 ===",
|
||||
"练习1:指针声明",
|
||||
"练习2:指针解引用",
|
||||
"练习3:指针作为函数参数",
|
||||
"练习4:指针零值",
|
||||
"练习5:指针与数组",
|
||||
}
|
||||
|
||||
for _, section := range requiredSections {
|
||||
if !strings.Contains(output, section) {
|
||||
t.Errorf("期望输出包含 '%s'", section)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
# 02-new-make - new vs make
|
||||
|
||||
## 知识点讲解
|
||||
|
||||
### new函数
|
||||
|
||||
```go
|
||||
p := new(int) // 返回指向int类型零值的指针
|
||||
fmt.Println(*p) // 输出: 0
|
||||
*p = 10 // 可以通过指针修改值
|
||||
```
|
||||
|
||||
**特点**:
|
||||
- 返回指向类型的零值指针
|
||||
- 适用于所有类型
|
||||
- 内存已初始化为零值但不执行构造逻辑
|
||||
|
||||
### make函数
|
||||
|
||||
```go
|
||||
// 创建切片
|
||||
s := make([]int, 5) // [0, 0, 0, 0, 0]
|
||||
s := make([]int, 3, 10) // 长度3, 容量10
|
||||
|
||||
// 创建map
|
||||
m := make(map[string]int)
|
||||
m["key"] = 100
|
||||
|
||||
// 创建channel
|
||||
ch := make(chan int)
|
||||
```
|
||||
|
||||
**特点**:
|
||||
- 只用于创建引用类型(slice、map、channel)
|
||||
- 返回的是初始化后的类型(非指针)
|
||||
- 会执行类型的初始化逻辑
|
||||
|
||||
### 主要区别
|
||||
|
||||
| 特性 | new() | make() |
|
||||
|------|-------|--------|
|
||||
| 返回类型 | 指针 | 值 |
|
||||
| 适用类型 | 所有类型 | slice, map, channel |
|
||||
| 初始化 | 仅零值 | 完整初始化 |
|
||||
| 常用场景 | 需要指针时 | 创建引用类型时 |
|
||||
|
||||
### 重要提示
|
||||
|
||||
- 使用 `new` 创建的指针指向零值
|
||||
- 使用 `make` 创建的引用类型可以直接使用
|
||||
- 不要用 `new` 创建切片、map或channel
|
||||
|
||||
## 学习目标
|
||||
|
||||
完成本练习后,你将:
|
||||
- ✅ 理解new和make的区别
|
||||
- ✅ 掌握new的使用场景
|
||||
- ✅ 掌握make的使用场景
|
||||
- ✅ 学会正确选择new或make
|
||||
|
||||
## 练习说明
|
||||
|
||||
打开 `main.go`,根据注释提示填充代码,完成后运行 `go test -v` 验证答案。
|
||||
@@ -0,0 +1,102 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func exercise1() int {
|
||||
fmt.Println("=== 练习1:new创建指针 ===")
|
||||
|
||||
// 使用new创建一个int类型的指针
|
||||
p := ____ // new返回指向int零值的指针
|
||||
|
||||
fmt.Printf("new创建的指针: %v, 解引用值: %d\n", p, ____)
|
||||
|
||||
*p = 10
|
||||
|
||||
fmt.Printf("修改后的值: %d\n", ____)
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise2() []int {
|
||||
fmt.Println("=== 练习2:make创建切片 ===")
|
||||
|
||||
// 使用make创建一个长度为5的int切片
|
||||
s := ____
|
||||
|
||||
fmt.Printf("创建的切片: %v, 长度: %d\n", s, ____)
|
||||
|
||||
fmt.Printf("切片的第一个元素: %d\n", s[____])
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise3() map[string]int {
|
||||
fmt.Println("=== 练习3:make创建map ===")
|
||||
|
||||
// 使用make创建一个map
|
||||
m := ____
|
||||
|
||||
m["张三"] = 90
|
||||
|
||||
fmt.Printf("map内容: %v\n", ____)
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise4() int {
|
||||
fmt.Println("=== 练习4:new vs make - 切片 ===")
|
||||
|
||||
// 分别使用new和make创建切片,观察区别
|
||||
newSlice := new([]int) // 返回指针,指向nil切片
|
||||
makeSlice := make([]int, 3) // 返回切片实例
|
||||
|
||||
fmt.Printf("new创建的切片: %v, 是否为nil: %t\n", ____, *newSlice == nil)
|
||||
fmt.Printf("make创建的切片: %v, 是否为nil: %t\n", ____, makeSlice == nil)
|
||||
|
||||
if *newSlice == nil {
|
||||
*newSlice = make([]int, 3)
|
||||
____[0] = 100
|
||||
}
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise5() string {
|
||||
fmt.Println("=== 练习5:new vs make - 结构体 ===")
|
||||
|
||||
// 使用new创建结构体指针
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
p := ____
|
||||
|
||||
fmt.Printf("new创建的结构体: %+v\n", ____)
|
||||
|
||||
p.Name = "张三"
|
||||
p.Age = 20
|
||||
|
||||
fmt.Printf("修改后的结构体: %+v\n", ____)
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== new vs make 练习 ===\n")
|
||||
|
||||
result1 := exercise1()
|
||||
fmt.Printf("练习1结果: %d\n", result1)
|
||||
|
||||
result2 := exercise2()
|
||||
fmt.Printf("练习2结果: %v\n", result2)
|
||||
|
||||
result3 := exercise3()
|
||||
fmt.Printf("练习3结果: %v\n", result3)
|
||||
|
||||
result4 := exercise4()
|
||||
fmt.Printf("练习4结果: %d\n", result4)
|
||||
|
||||
result5 := exercise5()
|
||||
fmt.Printf("练习5结果: %s\n", result5)
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func captureOutput(f func()) string {
|
||||
old := os.Stdout
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stdout = w
|
||||
|
||||
f()
|
||||
|
||||
w.Close()
|
||||
os.Stdout = old
|
||||
|
||||
var buf bytes.Buffer
|
||||
buf.ReadFrom(r)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func TestExercise1(t *testing.T) {
|
||||
result := exercise1()
|
||||
if result != 10 {
|
||||
t.Errorf("期望 10, 实际: %d", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise2(t *testing.T) {
|
||||
result := exercise2()
|
||||
if len(result) != 5 {
|
||||
t.Errorf("期望长度 5, 实际: %d", len(result))
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise3(t *testing.T) {
|
||||
result := exercise3()
|
||||
if len(result) != 1 {
|
||||
t.Errorf("期望长度 1, 实际: %d", len(result))
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise4(t *testing.T) {
|
||||
result := exercise4()
|
||||
if result != 100 {
|
||||
t.Errorf("期望 100, 实际: %d", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise5(t *testing.T) {
|
||||
result := exercise5()
|
||||
if result != "张三" {
|
||||
t.Errorf("期望 '张三', 实际: %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMainFunction(t *testing.T) {
|
||||
output := captureOutput(main)
|
||||
|
||||
requiredSections := []string{
|
||||
"=== new vs make 练习 ===",
|
||||
"练习1:new创建指针",
|
||||
"练习2:make创建切片",
|
||||
"练习3:make创建map",
|
||||
"练习4:new vs make - 切片",
|
||||
"练习5:new vs make - 结构体",
|
||||
}
|
||||
|
||||
for _, section := range requiredSections {
|
||||
if !strings.Contains(output, section) {
|
||||
t.Errorf("期望输出包含 '%s'", section)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
# 03-value-pointer - 值传递vs指针传递
|
||||
|
||||
## 知识点讲解
|
||||
|
||||
### 值传递
|
||||
|
||||
```go
|
||||
func modifyValue(x int) {
|
||||
x = 100 // 修改的是函数内的副本
|
||||
}
|
||||
|
||||
num := 10
|
||||
modifyValue(num)
|
||||
fmt.Println(num) // 输出: 10(原值不变)
|
||||
```
|
||||
|
||||
### 指针传递
|
||||
|
||||
```go
|
||||
func modifyPointer(p *int) {
|
||||
*p = 100 // 修改的是指针指向的值
|
||||
}
|
||||
|
||||
num := 10
|
||||
modifyPointer(&num)
|
||||
fmt.Println(num) // 输出: 100(原值被修改)
|
||||
```
|
||||
|
||||
### 结构体的值传递
|
||||
|
||||
```go
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
func modifyPersonValue(p Person) {
|
||||
p.Name = "李四" // 修改副本
|
||||
}
|
||||
|
||||
p := Person{Name: "张三", Age: 20}
|
||||
modifyPersonValue(p)
|
||||
fmt.Println(p.Name) // 输出: 张三(原值不变)
|
||||
```
|
||||
|
||||
### 结构体的指针传递
|
||||
|
||||
```go
|
||||
func modifyPersonPointer(p *Person) {
|
||||
p.Name = "李四" // 修改原值
|
||||
}
|
||||
|
||||
p := Person{Name: "张三", Age: 20}
|
||||
modifyPersonPointer(&p)
|
||||
fmt.Println(p.Name) // 输出: 李四(原值被修改)
|
||||
```
|
||||
|
||||
### 重要提示
|
||||
|
||||
- Go中所有参数传递都是值传递
|
||||
- 传递指针实际是拷贝指针地址,但通过指针可以修改原值
|
||||
- 大结构体使用指针传递可以避免大量拷贝
|
||||
- 切片、map等引用类型传递也具有类似指针的行为
|
||||
|
||||
## 学习目标
|
||||
|
||||
完成本练习后,你将:
|
||||
- ✅ 理解值传递和指针传递的区别
|
||||
- ✅ 掌握何时使用值传递
|
||||
- ✅ 掌握何时使用指针传递
|
||||
- ✅ 了解性能方面的考虑
|
||||
|
||||
## 练习说明
|
||||
|
||||
打开 `main.go`,根据注释提示填充代码,完成后运行 `go test -v` 验证答案。
|
||||
@@ -0,0 +1,130 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func modifyByValue(x int) int {
|
||||
// 值传递:修改函数内的副本
|
||||
x = ____
|
||||
return ____
|
||||
}
|
||||
|
||||
func modifyByPointer(p *int) int {
|
||||
// 指针传递:修改指针指向的值
|
||||
____ = ____
|
||||
return ____
|
||||
}
|
||||
|
||||
type Counter struct {
|
||||
Value int
|
||||
}
|
||||
|
||||
func (c Counter) Increment() int {
|
||||
// 值接收者:修改副本
|
||||
c.Value += 1
|
||||
return ____
|
||||
}
|
||||
|
||||
func (c *Counter) IncrementPointer() int {
|
||||
// 指针接收者:修改原值
|
||||
c.Value += ____
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise1() int {
|
||||
fmt.Println("=== 练习1:值传递 ===")
|
||||
|
||||
// 值传递不会修改原值
|
||||
num := 10
|
||||
|
||||
result := modifyByValue(____)
|
||||
|
||||
fmt.Printf("原值: %d, 函数返回值: %d\n", ____, result)
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise2() int {
|
||||
fmt.Println("=== 练习2:指针传递 ===")
|
||||
|
||||
// 指针传递会修改原值
|
||||
num := 10
|
||||
|
||||
result := ____
|
||||
|
||||
fmt.Printf("原值: %d, 函数返回值: %d\n", ____, result)
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise3() int {
|
||||
fmt.Println("=== 练习3:结构体值传递 ===")
|
||||
|
||||
// 值方法不会修改原结构体
|
||||
counter := Counter{Value: 0}
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
counter.____()
|
||||
}
|
||||
|
||||
fmt.Printf("原结构体值: %d\n", ____)
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise4() int {
|
||||
fmt.Println("=== 练习4:结构体指针传递 ===")
|
||||
|
||||
// 指针方法会修改原结构体
|
||||
counter := Counter{Value: 0}
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
counter.____()
|
||||
}
|
||||
|
||||
fmt.Printf("原结构体值: %d\n", ____)
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
type SliceContainer struct {
|
||||
Data []int
|
||||
}
|
||||
|
||||
func (s *SliceContainer) Add(value int) {
|
||||
// 指针方法可以修改切片内容
|
||||
s.Data = append(____, ____)
|
||||
}
|
||||
|
||||
func exercise5() []int {
|
||||
fmt.Println("=== 练习5:切片与结构体 ===")
|
||||
|
||||
// 使用切片的结构体
|
||||
container := SliceContainer{Data: []int{}}
|
||||
|
||||
container.Add(10)
|
||||
container.Add(20)
|
||||
container.Add(30)
|
||||
|
||||
fmt.Printf("切片内容: %v\n", ____)
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== 值传递 vs 指针传递 练习 ===\n")
|
||||
|
||||
result1 := exercise1()
|
||||
fmt.Printf("练习1结果: %d\n", result1)
|
||||
|
||||
result2 := exercise2()
|
||||
fmt.Printf("练习2结果: %d\n", result2)
|
||||
|
||||
result3 := exercise3()
|
||||
fmt.Printf("练习3结果: %d\n", result3)
|
||||
|
||||
result4 := exercise4()
|
||||
fmt.Printf("练习4结果: %d\n", result4)
|
||||
|
||||
result5 := exercise5()
|
||||
fmt.Printf("练习5结果: %v\n", result5)
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func captureOutput(f func()) string {
|
||||
old := os.Stdout
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stdout = w
|
||||
|
||||
f()
|
||||
|
||||
w.Close()
|
||||
os.Stdout = old
|
||||
|
||||
var buf bytes.Buffer
|
||||
buf.ReadFrom(r)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func TestExercise1(t *testing.T) {
|
||||
result := exercise1()
|
||||
if result != 10 {
|
||||
t.Errorf("期望 10, 实际: %d", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise2(t *testing.T) {
|
||||
result := exercise2()
|
||||
if result != 100 {
|
||||
t.Errorf("期望 100, 实际: %d", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise3(t *testing.T) {
|
||||
result := exercise3()
|
||||
if result != 0 {
|
||||
t.Errorf("期望 0, 实际: %d", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise4(t *testing.T) {
|
||||
result := exercise4()
|
||||
if result != 5 {
|
||||
t.Errorf("期望 5, 实际: %d", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise5(t *testing.T) {
|
||||
result := exercise5()
|
||||
expected := []int{10, 20, 30}
|
||||
if len(result) != len(expected) {
|
||||
t.Errorf("期望长度 %d, 实际: %d", len(expected), len(result))
|
||||
}
|
||||
for i, val := range expected {
|
||||
if result[i] != val {
|
||||
t.Errorf("索引 %d 期望 %d, 实际: %d", i, val, result[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMainFunction(t *testing.T) {
|
||||
output := captureOutput(main)
|
||||
|
||||
requiredSections := []string{
|
||||
"=== 值传递 vs 指针传递 练习 ===",
|
||||
"练习1:值传递",
|
||||
"练习2:指针传递",
|
||||
"练习3:结构体值传递",
|
||||
"练习4:结构体指针传递",
|
||||
"练习5:切片与结构体",
|
||||
}
|
||||
|
||||
for _, section := range requiredSections {
|
||||
if !strings.Contains(output, section) {
|
||||
t.Errorf("期望输出包含 '%s'", section)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
# 01-interfaces - 接口定义与实现
|
||||
|
||||
## 知识点讲解
|
||||
|
||||
### 接口定义
|
||||
|
||||
```go
|
||||
type Shape interface {
|
||||
Area() float64
|
||||
Perimeter() float64
|
||||
}
|
||||
```
|
||||
|
||||
### 接口实现
|
||||
|
||||
```go
|
||||
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)
|
||||
}
|
||||
```
|
||||
|
||||
**注意**:Go中接口是隐式实现的,不需要显式声明
|
||||
|
||||
### 多态
|
||||
|
||||
```go
|
||||
func printShapeInfo(s Shape) {
|
||||
fmt.Printf("面积: %.2f\n", s.Area())
|
||||
fmt.Printf("周长: %.2f\n", s.Perimeter())
|
||||
}
|
||||
|
||||
rect := Rectangle{Width: 10, Height: 5}
|
||||
circle := Circle{Radius: 7}
|
||||
|
||||
printShapeInfo(rect) // 可以传递Rectangle
|
||||
printShapeInfo(circle) // 也可以传递Circle
|
||||
```
|
||||
|
||||
### 空接口
|
||||
|
||||
```go
|
||||
var any interface{}
|
||||
any = 10
|
||||
any = "hello"
|
||||
any = []int{1, 2, 3}
|
||||
```
|
||||
|
||||
### 重要提示
|
||||
|
||||
- 接口定义一组方法签名
|
||||
- 任何类型只要实现了接口的所有方法,就自动实现了该接口
|
||||
- 空接口 `interface{}` 可以持有任何类型的值
|
||||
- 接口类型可以包含零个或多个方法
|
||||
|
||||
## 学习目标
|
||||
|
||||
完成本练习后,你将:
|
||||
- ✅ 掌握接口的定义方式
|
||||
- ✅ 学会实现接口
|
||||
- ✅ 理解多态的概念
|
||||
- ✅ 了解空接口的用法
|
||||
|
||||
## 练习说明
|
||||
|
||||
打开 `main.go`,根据注释提示填充代码,完成后运行 `go test -v` 验证答案。
|
||||
@@ -0,0 +1,155 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
type Shape interface {
|
||||
Area() float64
|
||||
Perimeter() float64
|
||||
}
|
||||
|
||||
type Rectangle struct {
|
||||
Width float64
|
||||
Height float64
|
||||
}
|
||||
|
||||
type Circle struct {
|
||||
Radius float64
|
||||
}
|
||||
|
||||
func (r Rectangle) Area() float64 {
|
||||
return ____
|
||||
}
|
||||
|
||||
func (r Rectangle) Perimeter() float64 {
|
||||
return ____
|
||||
}
|
||||
|
||||
func (c Circle) Area() float64 {
|
||||
return math.Pi * ____ * ____
|
||||
}
|
||||
|
||||
func (c Circle) Perimeter() float64 {
|
||||
return 2 * math.Pi * ____
|
||||
}
|
||||
|
||||
type ShapePrinter interface {
|
||||
PrintInfo()
|
||||
}
|
||||
|
||||
func (r Rectangle) PrintInfo() {
|
||||
fmt.Printf("矩形 - 宽: %.2f, 高: %.2f\n", ____, ____)
|
||||
}
|
||||
|
||||
func (c Circle) PrintInfo() {
|
||||
fmt.Printf("圆形 - 半径: %.2f\n", ____)
|
||||
}
|
||||
|
||||
func exercise1() float64 {
|
||||
fmt.Println("=== 练习1:矩形接口实现 ===")
|
||||
|
||||
rect := Rectangle{Width: 10, Height: 5}
|
||||
|
||||
area := ____
|
||||
perimeter := ____
|
||||
|
||||
fmt.Printf("矩形面积: %.2f, 周长: %.2f\n", area, perimeter)
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise2() string {
|
||||
fmt.Println("=== 练习2:圆形接口实现 ===")
|
||||
|
||||
circle := Circle{Radius: 7}
|
||||
|
||||
area := ____
|
||||
info := fmt.Sprintf("圆形面积: %.2f", area)
|
||||
|
||||
fmt.Println(____)
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise3() string {
|
||||
fmt.Println("=== 练习3:多态 ===")
|
||||
|
||||
// 定义一个Shape类型的变量,分别指向Rectangle和Circle
|
||||
var s Shape
|
||||
|
||||
s = ____
|
||||
fmt.Printf("形状类型: %T, 面积: %.2f\n", s, s.____())
|
||||
|
||||
s = ____
|
||||
fmt.Printf("形状类型: %T, 面积: %.2f\n", s, s.____())
|
||||
|
||||
return "多态演示完成"
|
||||
}
|
||||
|
||||
func exercise4() interface{} {
|
||||
fmt.Println("=== 练习4:空接口 ===")
|
||||
|
||||
// 空接口可以持有任何类型
|
||||
var data interface{}
|
||||
|
||||
data = ____
|
||||
fmt.Printf("数据: %v, 类型: %T\n", data, data)
|
||||
|
||||
data = ____
|
||||
fmt.Printf("数据: %v, 类型: %T\n", data, data)
|
||||
|
||||
data = ____
|
||||
fmt.Printf("数据: %v, 类型: %T\n", data, data)
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
type Animal interface {
|
||||
Sound() string
|
||||
}
|
||||
|
||||
type Dog struct{}
|
||||
|
||||
func (d Dog) Sound() string {
|
||||
return "汪汪"
|
||||
}
|
||||
|
||||
type Cat struct{}
|
||||
|
||||
func (c Cat) Sound() string {
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise5() string {
|
||||
fmt.Println("=== 练习5:接口组合与使用 ===")
|
||||
|
||||
// 创建Animal切片,包含不同的动物
|
||||
animals := []Animal{____, ____}
|
||||
|
||||
for _, animal := range ____ {
|
||||
fmt.Printf("动物发出的声音: %s\n", animal.____())
|
||||
}
|
||||
|
||||
return "动物接口演示完成"
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== 接口 练习 ===\n")
|
||||
|
||||
result1 := exercise1()
|
||||
fmt.Printf("练习1结果: %.2f\n", result1)
|
||||
|
||||
result2 := exercise2()
|
||||
fmt.Printf("练习2结果: %s\n", result2)
|
||||
|
||||
result3 := exercise3()
|
||||
fmt.Printf("练习3结果: %s\n", result3)
|
||||
|
||||
result4 := exercise4()
|
||||
fmt.Printf("练习4结果: %v (类型: %T)\n", result4, result4)
|
||||
|
||||
result5 := exercise5()
|
||||
fmt.Printf("练习5结果: %s\n", result5)
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func captureOutput(f func()) string {
|
||||
old := os.Stdout
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stdout = w
|
||||
|
||||
f()
|
||||
|
||||
w.Close()
|
||||
os.Stdout = old
|
||||
|
||||
var buf bytes.Buffer
|
||||
buf.ReadFrom(r)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func TestExercise1(t *testing.T) {
|
||||
result := exercise1()
|
||||
if result != 50 {
|
||||
t.Errorf("期望 50, 实际: %f", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise2(t *testing.T) {
|
||||
result := exercise2()
|
||||
if !strings.Contains(result, "圆形面积:") {
|
||||
t.Errorf("期望包含 '圆形面积:', 实际: %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise3(t *testing.T) {
|
||||
result := exercise3()
|
||||
if result != "多态演示完成" {
|
||||
t.Errorf("期望 '多态演示完成', 实际: %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise4(t *testing.T) {
|
||||
result := exercise4()
|
||||
if result == nil {
|
||||
t.Error("期望非nil值")
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise5(t *testing.T) {
|
||||
result := exercise5()
|
||||
if result != "动物接口演示完成" {
|
||||
t.Errorf("期望 '动物接口演示完成', 实际: %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMainFunction(t *testing.T) {
|
||||
output := captureOutput(main)
|
||||
|
||||
requiredSections := []string{
|
||||
"=== 接口 练习 ===",
|
||||
"练习1:矩形接口实现",
|
||||
"练习2:圆形接口实现",
|
||||
"练习3:多态",
|
||||
"练习4:空接口",
|
||||
"练习5:接口组合与使用",
|
||||
}
|
||||
|
||||
for _, section := range requiredSections {
|
||||
if !strings.Contains(output, section) {
|
||||
t.Errorf("期望输出包含 '%s'", section)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
# 02-methods - 方法定义
|
||||
|
||||
## 知识点讲解
|
||||
|
||||
### 方法定义
|
||||
|
||||
```go
|
||||
// 值接收者
|
||||
func (p Person) GetName() string {
|
||||
return p.Name
|
||||
}
|
||||
|
||||
// 指针接收者
|
||||
func (p *Person) SetName(name string) {
|
||||
p.Name = name
|
||||
}
|
||||
```
|
||||
|
||||
### 值接收者 vs 指针接收者
|
||||
|
||||
```go
|
||||
type Counter struct {
|
||||
value int
|
||||
}
|
||||
|
||||
func (c Counter) GetValue() int {
|
||||
return c.value // 只读,不修改原值
|
||||
}
|
||||
|
||||
func (c *Counter) Increment() {
|
||||
c.value++ // 值读写,修改原值
|
||||
}
|
||||
```
|
||||
|
||||
### 方法选择
|
||||
|
||||
| 场景 | 接收者类型 |
|
||||
|------|-----------|
|
||||
| 方法不需要修改接收者 | 值接收者 |
|
||||
| 方法需要修改接收者 | 指针接收者 |
|
||||
| 接收者较大,避免拷贝 | 指针接收者 |
|
||||
| 保持接口兼容性 | 值接收者 |
|
||||
|
||||
### 方法表达式与值
|
||||
|
||||
```go
|
||||
c := Counter{value: 10}
|
||||
|
||||
// 方法调用
|
||||
c.Increment()
|
||||
|
||||
// 方法表达式
|
||||
f := (*Counter).Increment
|
||||
f(&c)
|
||||
```
|
||||
|
||||
### 重要提示
|
||||
|
||||
- 值接收者可以用于指针类型,反之则需要Go自动转换
|
||||
- 方法集规则影响接口实现
|
||||
- 选择接收者类型要考虑一致性
|
||||
|
||||
## 学习目标
|
||||
|
||||
完成本练习后,你将:
|
||||
- ✅ 掌握方法的定义方式
|
||||
- ✅ 理解值接收者和指针接收者的区别
|
||||
- ✅ 学会为结构体定义方法
|
||||
- ✅ 掌握方法的选择原则
|
||||
|
||||
## 练习说明
|
||||
|
||||
打开 `main.go`,根据注释提示填充代码,完成后运行 `go test -v` 验证答案。
|
||||
@@ -0,0 +1,163 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
Email string
|
||||
}
|
||||
|
||||
func (p Person) GetName() string {
|
||||
return ____
|
||||
}
|
||||
|
||||
func (p Person) GetAge() int {
|
||||
return ____
|
||||
}
|
||||
|
||||
func (p *Person) SetName(name string) {
|
||||
____ = ____
|
||||
}
|
||||
|
||||
func (p *Person) SetEmail(email string) {
|
||||
____ = ____
|
||||
}
|
||||
|
||||
func (p Person) GetInfo() string {
|
||||
return fmt.Sprintf("%s, %d岁, %s", ____, ____, ____)
|
||||
}
|
||||
|
||||
type Rectangle struct {
|
||||
Width float64
|
||||
Height float64
|
||||
}
|
||||
|
||||
func (r Rectangle) Area() float64 {
|
||||
return ____
|
||||
}
|
||||
|
||||
func (r *Rectangle) Resize(width, height float64) {
|
||||
____ = ____
|
||||
____ = ____
|
||||
}
|
||||
|
||||
type BankAccount struct {
|
||||
Balance float64
|
||||
Owner string
|
||||
}
|
||||
|
||||
func (b *BankAccount) Deposit(amount float64) {
|
||||
b.Balance += ____
|
||||
}
|
||||
|
||||
func (b *BankAccount) Withdraw(amount float64) bool {
|
||||
if b.Balance >= amount {
|
||||
b.Balance -= ____
|
||||
return ____
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (b BankAccount) GetBalance() float64 {
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise1() string {
|
||||
fmt.Println("=== 练习1:基础方法 ===")
|
||||
|
||||
person := Person{Name: "张三", Age: 25, Email: "zhangsan@example.com"}
|
||||
|
||||
name := ____
|
||||
age := ____
|
||||
|
||||
person.SetName(____)
|
||||
person.SetEmail(____)
|
||||
|
||||
fmt.Printf("姓名: %s, 年龄: %d\n", ____, person.Age)
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise2() float64 {
|
||||
fmt.Println("=== 练习2:矩形方法 ===")
|
||||
|
||||
rect := Rectangle{Width: 10, Height: 5}
|
||||
|
||||
area := ____
|
||||
|
||||
fmt.Printf("矩形面积: %.2f\n", area)
|
||||
|
||||
rect.Resize(____, ____)
|
||||
|
||||
newArea := ____
|
||||
fmt.Printf("调整后面积: %.2f\n", ____)
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise3() float64 {
|
||||
fmt.Println("=== 练习3:银行账户方法 ===")
|
||||
|
||||
account := BankAccount{Balance: 1000, Owner: "张三"}
|
||||
|
||||
account.____(500)
|
||||
fmt.Printf("存款后余额: %.2f\n", account.____())
|
||||
|
||||
success := account.____(300)
|
||||
if success {
|
||||
fmt.Printf("取款成功,余额: %.2f\n", account.____())
|
||||
}
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise4() string {
|
||||
fmt.Println("=== 练习4:方法链 ===")
|
||||
|
||||
// 使用方法链调用
|
||||
person := Person{Name: "李四", Age: 30, Email: "lisi@example.com"}
|
||||
|
||||
person.SetName("李四(更新)").SetEmail("lisi_new@example.com")
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise5() int {
|
||||
fmt.Println("=== 练习5:计算器方法 ===")
|
||||
|
||||
type Calculator struct {
|
||||
value int
|
||||
}
|
||||
|
||||
calc := Calculator{value: 0}
|
||||
|
||||
calc.setValue := func(v int) {
|
||||
calc.value = v
|
||||
}
|
||||
|
||||
calc.setValue(10)
|
||||
|
||||
fmt.Printf("计算器值: %d\n", calc.value)
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== 方法 练习 ===\n")
|
||||
|
||||
result1 := exercise1()
|
||||
fmt.Printf("练习1结果: %s\n", result1)
|
||||
|
||||
result2 := exercise2()
|
||||
fmt.Printf("练习2结果: %.2f\n", result2)
|
||||
|
||||
result3 := exercise3()
|
||||
fmt.Printf("练习3结果: %.2f\n", result3)
|
||||
|
||||
result4 := exercise4()
|
||||
fmt.Printf("练习4结果: %s\n", result4)
|
||||
|
||||
result5 := exercise5()
|
||||
fmt.Printf("练习5结果: %d\n", result5)
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func captureOutput(f func()) string {
|
||||
old := os.Stdout
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stdout = w
|
||||
|
||||
f()
|
||||
|
||||
w.Close()
|
||||
os.Stdout = old
|
||||
|
||||
var buf bytes.Buffer
|
||||
buf.ReadFrom(r)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func TestExercise1(t *testing.T) {
|
||||
result := exercise1()
|
||||
if result != "张三(更新)" {
|
||||
t.Errorf("期望 '张三(更新)', 实际: %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise2(t *testing.T) {
|
||||
result := exercise2()
|
||||
if result != 80 {
|
||||
t.Errorf("期望 80, 实际: %f", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise3(t *testing.T) {
|
||||
result := exercise3()
|
||||
if result != 1200 {
|
||||
t.Errorf("期望 1200, 实际: %f", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise4(t *testing.T) {
|
||||
result := exercise4()
|
||||
if result != "李四(更新)" {
|
||||
t.Errorf("期望 '李四(更新)', 实际: %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise5(t *testing.T) {
|
||||
result := exercise5()
|
||||
if result != 10 {
|
||||
t.Errorf("期望 10, 实际: %d", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMainFunction(t *testing.T) {
|
||||
output := captureOutput(main)
|
||||
|
||||
requiredSections := []string{
|
||||
"=== 方法 练习 ===",
|
||||
"练习1:基础方法",
|
||||
"练习2:矩形方法",
|
||||
"练习3:银行账户方法",
|
||||
"练习4:方法链",
|
||||
"练习5:计算器方法",
|
||||
}
|
||||
|
||||
for _, section := range requiredSections {
|
||||
if !strings.Contains(output, section) {
|
||||
t.Errorf("期望输出包含 '%s'", section)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
# 03-embedding - 组合与类型断言
|
||||
|
||||
## 知识点讲解
|
||||
|
||||
### 结构体嵌入(组合)
|
||||
|
||||
```go
|
||||
type Address struct {
|
||||
City string
|
||||
Street string
|
||||
}
|
||||
|
||||
type Person struct {
|
||||
Name string
|
||||
Address Address // 嵌套结构体
|
||||
}
|
||||
|
||||
type Employee struct {
|
||||
Person // 匿名嵌入
|
||||
EmployeeID int
|
||||
}
|
||||
|
||||
emp := Employee{
|
||||
Person: Person{Name: "张三"},
|
||||
}
|
||||
fmt.Println(emp.Name) // 可以直接访问嵌入的字段
|
||||
```
|
||||
|
||||
### 接口嵌入
|
||||
|
||||
```go
|
||||
type Reader interface {
|
||||
Read() string
|
||||
}
|
||||
|
||||
type Writer interface {
|
||||
Write(s string)
|
||||
}
|
||||
|
||||
type ReadWriter interface {
|
||||
Reader
|
||||
Writer // 接口组合
|
||||
}
|
||||
```
|
||||
|
||||
### 类型断言
|
||||
|
||||
```go
|
||||
var i interface{} = "hello"
|
||||
|
||||
// 方式1:标准断言
|
||||
s := i.(string)
|
||||
|
||||
// 方式2:带检查
|
||||
s, ok := i.(string)
|
||||
if !ok {
|
||||
fmt.Println("类型断言失败")
|
||||
}
|
||||
```
|
||||
|
||||
### 类型选择
|
||||
|
||||
```go
|
||||
func printValue(v interface{}) {
|
||||
switch v.(type) {
|
||||
case int:
|
||||
fmt.Println("整数:", v)
|
||||
case string:
|
||||
fmt.Println("字符串:", v)
|
||||
default:
|
||||
fmt.Println("未知类型")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 重要提示
|
||||
|
||||
- Go使用组合而非继承
|
||||
- 结构体嵌入可以实现类似继承的效果
|
||||
- 类型断言若失败会panic,需谨慎使用
|
||||
- 类型选择用于处理多种类型
|
||||
|
||||
## 学习目标
|
||||
|
||||
完成本练习后,你将:
|
||||
- ✅ 掌握结构体嵌入的使用
|
||||
- ✅ 理解接口嵌入的概念
|
||||
- ✅ 学会使用类型断言
|
||||
- ✅ 掌握类型选择的使用
|
||||
|
||||
## 练习说明
|
||||
|
||||
打开 `main.go`,根据注释提示填充代码,完成后运行 `go test -v` 验证答案。
|
||||
@@ -0,0 +1,182 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Address struct {
|
||||
City string
|
||||
Street string
|
||||
}
|
||||
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
Address Address
|
||||
}
|
||||
|
||||
type Employee struct {
|
||||
Person
|
||||
EmployeeID int
|
||||
Department string
|
||||
}
|
||||
|
||||
type Employee2 struct {
|
||||
____
|
||||
Salary float64
|
||||
}
|
||||
|
||||
type Reader interface {
|
||||
Read() string
|
||||
}
|
||||
|
||||
type Writer interface {
|
||||
Write(s string)
|
||||
}
|
||||
|
||||
type File struct {
|
||||
Name string
|
||||
Content string
|
||||
}
|
||||
|
||||
func (f File) Read() string {
|
||||
return f.___
|
||||
}
|
||||
|
||||
func (f *File) Write(s string) {
|
||||
f.Content = ____
|
||||
}
|
||||
|
||||
type ReadWriter interface {
|
||||
____
|
||||
____
|
||||
}
|
||||
|
||||
func exercise1() string {
|
||||
fmt.Println("=== 练习1:结构体嵌入 ===")
|
||||
|
||||
emp := Employee{
|
||||
Person: Person{
|
||||
Name: "张三",
|
||||
Age: 30,
|
||||
},
|
||||
EmployeeID: 1001,
|
||||
Department: "技术部",
|
||||
}
|
||||
|
||||
fmt.Printf("员工姓名: %s, 年龄: %d\n", ____, emp.___)
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise2() string {
|
||||
fmt.Println("=== 练习2:多层嵌入 ===")
|
||||
|
||||
address := Address{City: "北京", Street: "长安街"}
|
||||
|
||||
emp2 := Employee2{
|
||||
Person: Person{
|
||||
Name: "李四",
|
||||
Address: ____,
|
||||
},
|
||||
Salary: 10000.0,
|
||||
}
|
||||
|
||||
fmt.Printf("员工: %s, 城市: %s\n", emp2.___, emp2.___.City)
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise3() string {
|
||||
fmt.Println("=== 练习3:接口实现 ===")
|
||||
|
||||
file := File{Name: "test.txt", Content: "初始内容"}
|
||||
|
||||
// 使用Read方法
|
||||
content := file.____()
|
||||
fmt.Printf("读取内容: %s\n", content)
|
||||
|
||||
// 使用Write方法
|
||||
file.____("新内容")
|
||||
fmt.Printf("写入后内容: %s\n", file.___)
|
||||
|
||||
return ___
|
||||
}
|
||||
|
||||
func exercise4() string {
|
||||
fmt.Println("=== 练习4:接口组合 ===")
|
||||
|
||||
file := &File{Name: "data.txt", "原始数据"}
|
||||
|
||||
var rw _____
|
||||
|
||||
rw.Write("修改后的数据")
|
||||
result := rw.Read()
|
||||
|
||||
fmt.Printf("读写结果: %s\n", result)
|
||||
|
||||
return ____
|
||||
}
|
||||
|
||||
func exercise5() string {
|
||||
fmt.Println("=== 练习5:类型断言 ===")
|
||||
|
||||
var data interface{} = "Hello, Go!"
|
||||
|
||||
// 尝试断言为string
|
||||
str, ok := data.____
|
||||
if ok {
|
||||
fmt.Printf("类型断言成功: %s\n", ____)
|
||||
}
|
||||
|
||||
// 尝试断言为int
|
||||
_, ok = data.____
|
||||
if !ok {
|
||||
fmt.Println("类型断言失败: 不是int类型")
|
||||
}
|
||||
|
||||
return "类型断言演示完成"
|
||||
}
|
||||
|
||||
func exercise6() string {
|
||||
fmt.Println("=== 练习6:类型选择 ===")
|
||||
|
||||
values := []interface{}{10, "hello", 3.14, true}
|
||||
|
||||
for _, v := range ____ {
|
||||
switch v.(type) {
|
||||
case int:
|
||||
fmt.Printf("整数: %d\n", ____)
|
||||
case string:
|
||||
fmt.Printf("字符串: %s\n", ____)
|
||||
case float64:
|
||||
fmt.Printf("浮点数: %.2f\n", ____)
|
||||
case bool:
|
||||
fmt.Printf("布尔值: %t\n", ____)
|
||||
default:
|
||||
fmt.Println("未知类型")
|
||||
}
|
||||
}
|
||||
|
||||
return "类型选择演示完成"
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== 组合与类型断言 练习 ===\n")
|
||||
|
||||
result1 := exercise1()
|
||||
fmt.Printf("练习1结果: %s\n", result1)
|
||||
|
||||
result2 := exercise2()
|
||||
fmt.Printf("练习2结果: %s\n", result2)
|
||||
|
||||
result3 := exercise3()
|
||||
fmt.Printf("练习3结果: %s\n", result3)
|
||||
|
||||
result4 := exercise4()
|
||||
fmt.Printf("练习4结果: %s\n", result4)
|
||||
|
||||
result5 := exercise5()
|
||||
fmt.Printf("练习5结果: %s\n", result5)
|
||||
|
||||
result6 := exercise6()
|
||||
fmt.Printf("练习6结果: %s\n", result6)
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func captureOutput(f func()) string {
|
||||
old := os.Stdout
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stdout = w
|
||||
|
||||
f()
|
||||
|
||||
w.Close()
|
||||
os.Stdout = old
|
||||
|
||||
var buf bytes.Buffer
|
||||
buf.ReadFrom(r)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func TestExercise1(t *testing.T) {
|
||||
result := exercise1()
|
||||
if result != "张三" {
|
||||
t.Errorf("期望 '张三', 实际: %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise2(t *testing.T) {
|
||||
result := exercise2()
|
||||
if result != "李四" {
|
||||
t.Errorf("期望 '李四', 实际: %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise3(t *testing.T) {
|
||||
result := exercise3()
|
||||
if result != "新内容" {
|
||||
t.Errorf("期望 '新内容', 实际: %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise4(t *testing.T) {
|
||||
result := exercise4()
|
||||
if result != "修改后的数据" {
|
||||
t.Errorf("期望 '修改后的数据', 实际: %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise5(t *testing.T) {
|
||||
result := exercise5()
|
||||
if result != "类型断言演示完成" {
|
||||
t.Errorf("期望 '类型断言演示完成', 实际: %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExercise6(t *testing.T) {
|
||||
result := exercise6()
|
||||
if result != "类型选择演示完成" {
|
||||
t.Errorf("期望 '类型选择演示完成', 实际: %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMainFunction(t *testing.T) {
|
||||
output := captureOutput(main)
|
||||
|
||||
requiredSections := []string{
|
||||
"=== 组合与类型断言 练习 ===",
|
||||
"练习1:结构体嵌入",
|
||||
"练习2:多层嵌入",
|
||||
"练习3:接口实现",
|
||||
"练习4:接口组合",
|
||||
"练习5:类型断言",
|
||||
"练习6:类型选择",
|
||||
}
|
||||
|
||||
for _, section := range requiredSections {
|
||||
if !strings.Contains(output, section) {
|
||||
t.Errorf("期望输出包含 '%s'", section)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user