yumaojun03 1aa8ec7f3e ```
feat: 添加Go语言函数式编程和结构体进阶教程

- 新增Reduce函数实现map-reduce模式
- 实现装饰器模式wrapper函数
- 添加函数闭包和计数器功能
- 完善结构体方法、继承、组合和重写机制
- 增加JSON序列化反序列化及标签处理
- 创建新的学习章节day04关于结构体进阶内容
- 更新README目录结构包含新章节
```
2026-02-01 16:00:12 +08:00

252 lines
5.9 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"fmt"
"os"
)
func main() {
// 2, 3 实参: 实际传递的参数
// x = 2, y = 3
fmt.Println(sum(2, 3))
// 切片作为参数传递(通过切片来包装多个参数)和多个参数
fmt.Println(sum2([]int{2, 3, 4}))
fmt.Println(sum3(2, 3, 4))
// _ = sum3(2, 3, 4)
// 引用类型示例 底层扩容的影响
// -> 底层数组A未扩容
arg1 := []int{2, 3, 4}
result1 := appendAndChange(arg1)
fmt.Println(result1)
arg2 := []int{2, 3, 4}
appendAndChangeV2(&arg2)
fmt.Println(arg2)
// 1. 普通函数名作为参数传递, logfn, 把处理抽象成函数,往往是为了复用这段代码
// 2. 匿名函数, 临时使用一次,不需要复用
// logfn := func(log string) {
// fmt.Println(log)
// }
// 3. 临时使用,直接定义匿名函数,不需要赋值给变量
// logfn func(string), Go里面非常常见的写法(90%)
TaskHandler(&RunTaskRequest{Name: "task1"}, func(s string) {
fmt.Println(s)
})
counterFn := counter()
fmt.Println(counterFn(), counterFn(), counterFn())
// fib
fmt.Println(fib(5))
fmt.Println(fib(9))
// 变量目录, 打印了文件名称
walkDir(".", func(filePath string) {
fmt.Println(filePath)
})
//
fmt.Println(Reduce([]int{1, 2, 3, 4}, 0, func(init int, target int) int {
return init + target
}))
wrapper, counter := Wrapper(func() {
logfn("hello")
})
wrapper()
fmt.Println("", counter())
}
func logfn(log string) {
fmt.Println(log)
}
// (x int, y int)
// (x,y int)
// var x int
// var y int
// x, y: 形参: 形式参数 (函数定义时的参数,声明的参数)
func sum(x int, y int) int {
return x + y
}
// 切片作为参数传递, 把多个值传递给函数
// 用的时候需要构造切片 []int{2, 3, 4}
func sum2(nums []int) (total int) {
// var total int
for _, num := range nums {
total += num
}
return total
}
// 能不能让函数之间接收多个不确定的参数
// ...int: 不定长参数 --> []int
func sum3(args ...int) (total int) {
// var total int
for _, arg := range args {
total += arg
}
return total
}
// x-> 底层数组指针lencap
// y = x
// y-> 底层数组指针lencap
func appendAndChange(s []int) []int {
fmt.Println(s, len(s), cap(s))
s[0] = 9 // 影响外部底层数组(底层数组未扩容时(A))
s = append(s, 10, 11) // 可能扩容,之后的修改不再影响外部 3 -> 6
fmt.Println(s, len(s), cap(s))
s[0] = 8 // 这一行只影响内部副本(若已扩容(B))
return s
}
// []int -> x
// *[]int -> box(x)
func appendAndChangeV2(s *[]int) {
// 指针的值 copy 到了 v
// []int
// v := *s
// 产生一个新的值复杂对象(赋值的是元数据)
// box(x) -> x
// 这里的v 就不再是s (v值), v 是 s值的一个快照
// 不是操作这个地址本身,操作的是 值
fmt.Println(s, len(*s), cap(*s))
(*s)[0] = 9 // 影响外部底层数组(底层数组未扩容时(A))
// 解开box, 把 10 11 放进去
// s 的扩容就就是box 扩容了,对我们外部可见
*s = append(*s, 10, 11) // 可能扩容,之后的修改不再影响外部 3 -> 6
fmt.Println(s, len(*s), cap(*s))
// 解开box, 看的是扩容后的数组, 真的新的数组进行值的修改对当前box生效
(*s)[0] = 8 // 这一行只影响内部副本(若已扩容(B))
}
type RunTaskRequest struct {
Name string
Params map[string]string
}
// 出来过程中 有报错怎么 返回给调用方
// 执行过程中的日志 怎么返回给调用方
// 同步调用,必须等待任务执行完毕,才能拿到结果
// 通过回调的方式快速 返回给调用方
// 回调函数: 函数作为参数传递
// TaskHandler func(*Task) []string
func TaskHandler(req *RunTaskRequest, logfn func(string)) {
// return []string{"log1", "log2"}
// 执行任务过程中的日志 通过 logfn 回调函数返回给调用方
logfn("任务开始")
logfn("任务进行中...")
logfn("任务结束")
}
func counter() func() int {
// 依赖的变量
i := 0
// m 会被GC回收掉, 外部没有引用记录,意思就是被用完了
m := 10
fmt.Println(i, m)
// i 还被返回的依赖者, 除非这个函数不用了 i才会被回收
return func() int {
i++
return i
}
}
// 斐波那契数列 fn(n) = fn(n-1) + fn(n-2)
// 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...
// fib(5) = fib(4) + fib(3)
// fig(2) = 1: n=2 fib(1) + fib(0)
// fib(0) = 0
// fib(1) = 1
// fib(2) = fib(1) + fib(0) = 1
// fib(3) = fib(2) + fib(1) = 1 + 1 = 2
// fib(4) = fib(3) + fib(2) = 2 + 1 = 3
// fib(5) = fib(4) + fib(3) = 3 + 2 = 5
// 函数作为参数传递, 递归调用,知道退出
// 1: 1
// 2: 1
// 3: 2
// 4: 3
// 5: 5
// 6: 8
// 7: 13
// 8: 21
// 9: 34
// fib(5) = fib(4) + fib(3)
// fib(4) = fib(2) + fib(1) + fib(2)
// fib(3) = fib(2) + fib(1)
// fib(5) = fib(2) + fib(1) + fib(2) + fib(2) + fib(1) = 1 + 1 + 1 + 1 + 1 = 5
func fib(n int) int {
fmt.Println("fib:", n)
switch {
// 第一个
case n <= 0:
return 0
// 第2个
case n <= 2:
return 1
default:
// 有了2个
return fib(n-1) + fib(n-2)
}
}
// 最常见的就是 遍历目录里面的文件
func walkDir(path string, fn func(string)) {
files, _ := os.ReadDir(path)
// 读取path目录下的文件和子目录
for _, file := range files {
// 如果是目录, 继续往下找
if file.IsDir() {
walkDir(path+"/"+file.Name(), fn)
} else {
// 文件, 调用fn函数处理
fn(path + "/" + file.Name())
}
}
}
// Reduce([1 2 3], 0, +) -> 6
// 处理函数 处理聚会方式
func Reduce(nums []int, init int, fn func(init int, target int) int) int {
if len(nums) == 0 {
return init
}
var sum int
for _, num := range nums {
sum += fn(init, num)
}
return sum
}
// 装饰器模式, 函数增强
// @函数作为参数传递
func Wrapper(fn func()) (func(), func() int) {
// 统计函数调用测试
count := 0
return func() {
count++
fmt.Println("开始")
fn()
fmt.Println("结束")
}, func() int {
return count
}
}