Go高级教程:反射 (Reflection) 实战

大家好,我是极客老墨。 反射 (Reflection) 赋予了程序在运行时检查和修改自身状态的能力。从 JSON 解析到 ORM 框架(如 GORM),再到依赖注入,它们的底层都离不开反射。有人说"反射是魔鬼",也有人说"没有反射,就没有现代 Web 框架"。这篇就带你拆解 reflect 包,学会如何在运行时动态操作对象。 1. 核心概念:Type 和 Value 在 reflect 包中,有两位绝对主角: reflect.Type:这是啥?(类型信息,如 int, string, User) reflect.Value:这值多少?(具体的数据,如 42, “hello”, User{Name:“Hank”}) 一切反射操作的起点都是 interface{}。 1package main 2 3import ( 4 "fmt" 5 "reflect" 6) 7 8func main() { 9 x := 3.14 10 11 // 1. 获取类型 12 t := reflect.TypeOf(x) 13 fmt.Println("Type:", t) // float64 14 15 // 2. 获取值 16 v := reflect.ValueOf(x) 17 fmt.Println("Value:", v) // 3.14 18} graph LR subgraph iface ["interface{}"] direction TB TypePtr["_type pointer"] DataPtr["data pointer"] end TypePtr -->|"reflect.TypeOf"| RType["reflect.Type"] DataPtr -->|"reflect.ValueOf"| RValue["reflect.Value"] style iface fill:#f9f9f9,stroke:#333,stroke-width:2px,color:#333 style TypePtr fill:#e1f5fe,stroke:#01579b,color:#01579b style DataPtr fill:#e1f5fe,stroke:#01579b,color:#01579b style RType fill:#fff9c4,stroke:#fbc02d,color:#333 style RValue fill:#fff9c4,stroke:#fbc02d,color:#333 2. 三大反射定律 Go 的反射有三条铁律(出自 Rob Pike): ...

2026-01-28 · 3 min · 485 words · 老墨

Go高级教程:其他并发工具

大家好,我是极客老墨。 Goroutine 和 Channel 是 Go 并发的基础,但有些场景它们不够用。频繁创建对象导致 GC 压力大?用 sync.Pool。并发读写 map 会 panic?用 sync.Map。简单的计数器用锁太重?用 atomic。 这篇就聊聊 Go 的高级并发工具,看看它们各自适合什么场景。 sync.Pool:对象复用 频繁创建和销毁大对象会给 GC 带来压力,sync.Pool 用于对象复用。 基本用法 1package main 2 3import ( 4 "fmt" 5 "sync" 6) 7 8// 创建对象池 9var bufferPool = sync.Pool{ 10 // New 函数:池为空时创建新对象 11 New: func() interface{} { 12 fmt.Println("Creating new buffer") 13 return make([]byte, 1024) 14 }, 15} 16 17func main() { 18 // 从池中获取对象 19 buf := bufferPool.Get().([]byte) 20 21 // 使用对象 22 copy(buf, []byte("Hello, World!")) 23 fmt.Println(string(buf[:13])) 24 25 // 归还到池中 26 bufferPool.Put(buf) 27 28 // 再次获取(会复用刚才的对象) 29 buf2 := bufferPool.Get().([]byte) 30 fmt.Println(string(buf2[:13])) // 还是 "Hello, World!" 31} 要点: ...

2025-12-20 · 9 min · 1831 words · 老墨

Go高级教程:深入理解 GMP 调度器

大家好,我是极客老墨。 为什么 Go 语言能轻松支撑百万并发?为什么 Goroutine 切换成本这么低?这一切的背后,都站着一位神秘的大管家——GMP 调度器。这篇就用通俗易懂的语言,配合生动的比喻,带你深入理解 Go 高并发的核心秘密。 1. 为什么需要 GMP? 在很久很久以前(其实也就几十年前),我们写代码都是直接跟 线程 (Thread) 打交道。线程是操作系统(OS)调度的最小单位。 但是,线程这玩意儿太"贵"了: 内存占用高:一个线程栈大概要几 MB。 切换成本大:线程切换需要陷入内核态,保存寄存器、上下文,这简直就是"劳民伤财"。 这时候,Go 语言的设计师们拍案而起:“我们要造一种更轻量的线程!” 于是,Goroutine (协程) 诞生了。它初始只要几 KB,切换成本极低。 这就带来了一个问题:操作系统只认识线程,不认识 Goroutine。谁来负责把成千上万个 Goroutine 分配给 CPU 跑呢? 这就需要一个"中间商" —— Go 运行时调度器 (Scheduler)。 图示: Thread 与 Goroutine 的区别 2. GMP 模型大揭秘 GMP 其实是三个角色的缩写: G (Goroutine):我们写的代码任务,也就是协程。 M (Machine):工作线程(Thread),对应操作系统的真实线程。它是真正的干活人(搬砖工)。 P (Processor):逻辑处理器(Context),可以理解为"调度上下文"或"资源"。它是包工头,负责管理 G,并把 G 交给 M 去执行。 形象的比喻 想象一个大型搬砖工地: G (砖头):待搬运的任务。 M (工人):负责搬砖的劳动力。 P (手推车):工人必须推着车才能搬砖(因为车里装着搬砖工具和任务清单)。 如果没有 P(手推车),M(工人)就不知道该干啥。 ...

2025-11-28 · 2 min · 364 words · 老墨