Go 1.26.4 超深度分析 --- context + reflect + errors
核心源码:
context/context.go(806行) +reflect/type.go(2939行) +reflect/value.go(3865行) +errors/errors.go+errors/wrap.go
一、context --- 上下文传播
1.1 模块定位
context 包实现请求级的取消/超时/值传播:
- 跨 goroutine 取消信号传播
- 跨 API 边界传递截止时间
- 请求级数据传递(非参数传递)
1.2 Context 接口
go
type Context interface {
Deadline() (deadline time.Time, ok bool) // 截止时间
Done() <-chan struct{} // 取消信号
Err() error // 取消原因
Value(key any) any // 请求级值
}
1.3 四种实现
| 类型 | 功能 | 创建函数 |
|---|---|---|
emptyCtx |
空实现(永不取消) | context.Background() / TODO() |
cancelCtx |
可取消 | WithCancel(parent) |
timerCtx |
可取消+截止时间 | WithDeadline/WithTimeout(parent) |
valueCtx |
携带值 | WithValue(parent, key, val) |
#mermaid-svg-uXi4PWlj5NI6dJYq{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-uXi4PWlj5NI6dJYq .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-uXi4PWlj5NI6dJYq .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-uXi4PWlj5NI6dJYq .error-icon{fill:#552222;}#mermaid-svg-uXi4PWlj5NI6dJYq .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-uXi4PWlj5NI6dJYq .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-uXi4PWlj5NI6dJYq .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-uXi4PWlj5NI6dJYq .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-uXi4PWlj5NI6dJYq .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-uXi4PWlj5NI6dJYq .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-uXi4PWlj5NI6dJYq .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-uXi4PWlj5NI6dJYq .marker{fill:#333333;stroke:#333333;}#mermaid-svg-uXi4PWlj5NI6dJYq .marker.cross{stroke:#333333;}#mermaid-svg-uXi4PWlj5NI6dJYq svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-uXi4PWlj5NI6dJYq p{margin:0;}#mermaid-svg-uXi4PWlj5NI6dJYq g.classGroup text{fill:#9370DB;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-uXi4PWlj5NI6dJYq g.classGroup text .title{font-weight:bolder;}#mermaid-svg-uXi4PWlj5NI6dJYq .cluster-label text{fill:#333;}#mermaid-svg-uXi4PWlj5NI6dJYq .cluster-label span{color:#333;}#mermaid-svg-uXi4PWlj5NI6dJYq .cluster-label span p{background-color:transparent;}#mermaid-svg-uXi4PWlj5NI6dJYq .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-uXi4PWlj5NI6dJYq .cluster text{fill:#333;}#mermaid-svg-uXi4PWlj5NI6dJYq .cluster span{color:#333;}#mermaid-svg-uXi4PWlj5NI6dJYq .nodeLabel,#mermaid-svg-uXi4PWlj5NI6dJYq .edgeLabel{color:#131300;}#mermaid-svg-uXi4PWlj5NI6dJYq .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-uXi4PWlj5NI6dJYq .label text{fill:#131300;}#mermaid-svg-uXi4PWlj5NI6dJYq .labelBkg{background:#ECECFF;}#mermaid-svg-uXi4PWlj5NI6dJYq .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-uXi4PWlj5NI6dJYq .classTitle{font-weight:bolder;}#mermaid-svg-uXi4PWlj5NI6dJYq .node rect,#mermaid-svg-uXi4PWlj5NI6dJYq .node circle,#mermaid-svg-uXi4PWlj5NI6dJYq .node ellipse,#mermaid-svg-uXi4PWlj5NI6dJYq .node polygon,#mermaid-svg-uXi4PWlj5NI6dJYq .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-uXi4PWlj5NI6dJYq .divider{stroke:#9370DB;stroke-width:1;}#mermaid-svg-uXi4PWlj5NI6dJYq g.clickable{cursor:pointer;}#mermaid-svg-uXi4PWlj5NI6dJYq g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-uXi4PWlj5NI6dJYq g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-uXi4PWlj5NI6dJYq .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-uXi4PWlj5NI6dJYq .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-uXi4PWlj5NI6dJYq .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-uXi4PWlj5NI6dJYq .dashed-line{stroke-dasharray:3;}#mermaid-svg-uXi4PWlj5NI6dJYq .dotted-line{stroke-dasharray:1 2;}#mermaid-svg-uXi4PWlj5NI6dJYq #compositionStart,#mermaid-svg-uXi4PWlj5NI6dJYq .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-uXi4PWlj5NI6dJYq #compositionEnd,#mermaid-svg-uXi4PWlj5NI6dJYq .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-uXi4PWlj5NI6dJYq #dependencyStart,#mermaid-svg-uXi4PWlj5NI6dJYq .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-uXi4PWlj5NI6dJYq #dependencyStart,#mermaid-svg-uXi4PWlj5NI6dJYq .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-uXi4PWlj5NI6dJYq #extensionStart,#mermaid-svg-uXi4PWlj5NI6dJYq .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-uXi4PWlj5NI6dJYq #extensionEnd,#mermaid-svg-uXi4PWlj5NI6dJYq .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-uXi4PWlj5NI6dJYq #aggregationStart,#mermaid-svg-uXi4PWlj5NI6dJYq .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-uXi4PWlj5NI6dJYq #aggregationEnd,#mermaid-svg-uXi4PWlj5NI6dJYq .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-uXi4PWlj5NI6dJYq #lollipopStart,#mermaid-svg-uXi4PWlj5NI6dJYq .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-uXi4PWlj5NI6dJYq #lollipopEnd,#mermaid-svg-uXi4PWlj5NI6dJYq .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-uXi4PWlj5NI6dJYq .edgeTerminals{font-size:11px;line-height:initial;}#mermaid-svg-uXi4PWlj5NI6dJYq .classTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-uXi4PWlj5NI6dJYq .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-uXi4PWlj5NI6dJYq .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-uXi4PWlj5NI6dJYq :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} parent
embed
parent
<<interface>>
Context
+Deadline()(time.Time, bool)
+Done() : <-chan struct
+Err() : error
+Value(key any) : any
emptyCtx
+Deadline()(time.Time, false)
+Done() : nil
+Err() : nil
+Value(key) : nil
cancelCtx
-Context parent
-mu sync.Mutex
-done chan struct
-children mapcancelerstruct
-err error
+cancel(removeFromParent bool, err error)
timerCtx
-cancelCtx
-deadline time.Time
-timer *time.Timer
+Deadline()(time.Time, true)
valueCtx
-Context parent
-key, val any
+Value(key) : any
1.4 WithCancel --- 取消传播
go
func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
c := withCancelInput(parent)
if c.done == nil {
c = newCancelCtx(parent)
}
// 将自己加入 parent 的 children
propagateCancel(parent, c)
return c, func() { c.cancel(true, Canceled) }
}
propagateCancel --- 取消链建立
go
func propagateCancel(parent Context, child canceler) {
// 1. 如果 parent 已经取消 → 立即取消 child
if parent.Done() == nil {
return // parent 永不取消 → 不需要传播
}
if parent.Err() != nil {
child.cancel(false, parent.Err()) // parent 已取消
return
}
// 2. 获取 parent 的 cancelCtx
p, ok := parent.Value(&cancelCtxKey).(*cancelCtx)
if !ok {
// parent 不是 cancelCtx → 启动 goroutine 监听
go func() {
select {
case <-parent.Done():
child.cancel(false, parent.Err())
case <-child.Done():
}
}()
return
}
// 3. 将 child 加入 parent.children
p.mu.Lock()
if p.err != nil {
p.mu.Unlock()
child.cancel(false, p.err) // parent 已取消
} else {
if p.children == nil {
p.children = make(map[canceler]struct{})
}
p.children[child] = struct{}{}
p.mu.Unlock()
}
}
cancel --- 取消操作
go
func (c *cancelCtx) cancel(removeFromParent bool, err error) {
c.mu.Lock()
if c.err != nil {
c.mu.Unlock()
return // 已取消
}
c.err = err
if c.done == nil {
c.done = closedchan // 复用已关闭的 channel
} else {
close(c.done) // ★ 关闭 done channel → 所有监听者收到信号
}
// 递归取消所有 children
for child := range c.children {
child.cancel(false, err)
}
c.children = nil
c.mu.Unlock()
if removeFromParent {
removeFromParent(c) // 从 parent 的 children 中移除
}
}
取消传播时序
Goroutine B Goroutine A Child2 Child1 Parent cancelCtx Goroutine B Goroutine A Child2 Child1 Parent cancelCtx #mermaid-svg-nZACRF5nVCY79MfV{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-nZACRF5nVCY79MfV .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-nZACRF5nVCY79MfV .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-nZACRF5nVCY79MfV .error-icon{fill:#552222;}#mermaid-svg-nZACRF5nVCY79MfV .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-nZACRF5nVCY79MfV .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-nZACRF5nVCY79MfV .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-nZACRF5nVCY79MfV .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-nZACRF5nVCY79MfV .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-nZACRF5nVCY79MfV .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-nZACRF5nVCY79MfV .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-nZACRF5nVCY79MfV .marker{fill:#333333;stroke:#333333;}#mermaid-svg-nZACRF5nVCY79MfV .marker.cross{stroke:#333333;}#mermaid-svg-nZACRF5nVCY79MfV svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-nZACRF5nVCY79MfV p{margin:0;}#mermaid-svg-nZACRF5nVCY79MfV .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-nZACRF5nVCY79MfV text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-nZACRF5nVCY79MfV .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-nZACRF5nVCY79MfV .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-nZACRF5nVCY79MfV .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-nZACRF5nVCY79MfV .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-nZACRF5nVCY79MfV #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-nZACRF5nVCY79MfV .sequenceNumber{fill:white;}#mermaid-svg-nZACRF5nVCY79MfV #sequencenumber{fill:#333;}#mermaid-svg-nZACRF5nVCY79MfV #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-nZACRF5nVCY79MfV .messageText{fill:#333;stroke:none;}#mermaid-svg-nZACRF5nVCY79MfV .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-nZACRF5nVCY79MfV .labelText,#mermaid-svg-nZACRF5nVCY79MfV .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-nZACRF5nVCY79MfV .loopText,#mermaid-svg-nZACRF5nVCY79MfV .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-nZACRF5nVCY79MfV .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-nZACRF5nVCY79MfV .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-nZACRF5nVCY79MfV .noteText,#mermaid-svg-nZACRF5nVCY79MfV .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-nZACRF5nVCY79MfV .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-nZACRF5nVCY79MfV .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-nZACRF5nVCY79MfV .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-nZACRF5nVCY79MfV .actorPopupMenu{position:absolute;}#mermaid-svg-nZACRF5nVCY79MfV .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-nZACRF5nVCY79MfV .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-nZACRF5nVCY79MfV .actor-man circle,#mermaid-svg-nZACRF5nVCY79MfV line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-nZACRF5nVCY79MfV :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} cancel() 被调用 propagateCancel → 加入 childrenpropagateCancel → 加入 children<-child1.Done() (阻塞)<-child2.Done() (阻塞)close(done)child1.cancel(false, err)child2.cancel(false, err)close(child1.done)close(child2.done)<-child1.Done() 收到信号<-child2.Done() 收到信号
1.5 WithDeadline --- 截止时间
go
func WithDeadline(parent Context, d time.Time) (Context, CancelFunc) {
// 如果 parent 的截止时间更早 → 不需要新 timer
if cur, ok := parent.Deadline(); ok && cur.Before(d) {
return WithCancel(parent)
}
c := &timerCtx{
cancelCtx: newCancelCtx(parent),
deadline: d,
}
propagateCancel(parent, c)
// 计算超时时间
dur := time.Until(d)
if dur <= 0 {
c.cancel(true, DeadlineExceeded) // 已超时
return c, func() { c.cancel(false, Canceled) }
}
c.mu.Lock()
defer c.mu.Unlock()
if c.err == nil {
c.timer = time.AfterFunc(dur, func() {
c.cancel(true, DeadlineExceeded)
})
}
return c, func() { c.cancel(true, Canceled) }
}
1.6 WithValue --- 值传递
go
type valueCtx struct {
Context
key, val any
}
func (c *valueCtx) Value(key any) any {
// 逐级向上查找
if c.key == key {
return c.val
}
return c.Context.Value(key) // 递归查找 parent
}
设计要点:值查找是 O(深度) 链式查找,不适合高频使用。
二、reflect --- 运行时反射
2.1 模块定位
reflect 包实现运行时类型检查和值操作:
TypeOf: 获取动态类型信息ValueOf: 获取可操作的值MakeFunc: 动态创建函数DeepEqual: 深度比较
2.2 Type 接口
go
type Type interface {
Align() int
FieldAlign() int
Method(int) Method
NumMethod() int
Name() string
PkgPath() string
Size() uintptr
String() string
Kind() Kind
Implements(u Type) bool
AssignableTo(u Type) bool
ConvertibleTo(u Type) bool
NumField() int
Field(i int) StructField
Key() Type
Elem() Type
// ... 30+ 方法
}
2.3 rtype --- 底层类型表示
go
type rtype struct {
size uintptr // 类型大小
ptrBytes uintptr // 指针占用的字节数
hash uint32 // 类型哈希
tflag tflag // 类型标志
align uint8 // 对齐
fieldAlign uint8 // 字段对齐
kind uint8 // Kind 枚举
equal func(unsafe.Pointer, unsafe.Pointer) bool // 相等比较函数
gcdata unsafe.Pointer // GC 数据
str nameOff // 名称偏移
ptrToThis typeOff // 指向此类型的指针类型偏移
}
2.4 Value 结构
go
type Value struct {
typ *rtype // 类型指针
ptr unsafe.Pointer // 数据指针
flag // 标志位 (kind + flags)
}
flag 位图
| 位域 | 描述 |
|---|---|
flagKindMask |
低位: Kind 枚举 |
flagStickyRO |
粘性只读(未导出字段) |
flagEmbedRO |
嵌入只读(未导出嵌入字段) |
flagIndir |
ptr 是间接指针(指向堆) |
flagAddr |
可取地址 |
flagMethod |
是方法值 |
2.5 Value 核心方法
go
func (v Value) Interface() any {
// 将 Value 转回 interface{}
return v.interface()
}
func (v Value) Elem() Value {
// 解引用指针/接口/slice/array/map/channel
...
}
func (v Value) Field(i int) Value {
// 获取结构体第 i 个字段
...
}
func (v Value) Call(in []Value) []Value {
// 调用函数/方法
...
}
reflect.Value 操作链
#mermaid-svg-rEUhbyIqgMA48rJ5{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-rEUhbyIqgMA48rJ5 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-rEUhbyIqgMA48rJ5 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-rEUhbyIqgMA48rJ5 .error-icon{fill:#552222;}#mermaid-svg-rEUhbyIqgMA48rJ5 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-rEUhbyIqgMA48rJ5 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-rEUhbyIqgMA48rJ5 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-rEUhbyIqgMA48rJ5 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-rEUhbyIqgMA48rJ5 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-rEUhbyIqgMA48rJ5 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-rEUhbyIqgMA48rJ5 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-rEUhbyIqgMA48rJ5 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-rEUhbyIqgMA48rJ5 .marker.cross{stroke:#333333;}#mermaid-svg-rEUhbyIqgMA48rJ5 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-rEUhbyIqgMA48rJ5 p{margin:0;}#mermaid-svg-rEUhbyIqgMA48rJ5 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-rEUhbyIqgMA48rJ5 .cluster-label text{fill:#333;}#mermaid-svg-rEUhbyIqgMA48rJ5 .cluster-label span{color:#333;}#mermaid-svg-rEUhbyIqgMA48rJ5 .cluster-label span p{background-color:transparent;}#mermaid-svg-rEUhbyIqgMA48rJ5 .label text,#mermaid-svg-rEUhbyIqgMA48rJ5 span{fill:#333;color:#333;}#mermaid-svg-rEUhbyIqgMA48rJ5 .node rect,#mermaid-svg-rEUhbyIqgMA48rJ5 .node circle,#mermaid-svg-rEUhbyIqgMA48rJ5 .node ellipse,#mermaid-svg-rEUhbyIqgMA48rJ5 .node polygon,#mermaid-svg-rEUhbyIqgMA48rJ5 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-rEUhbyIqgMA48rJ5 .rough-node .label text,#mermaid-svg-rEUhbyIqgMA48rJ5 .node .label text,#mermaid-svg-rEUhbyIqgMA48rJ5 .image-shape .label,#mermaid-svg-rEUhbyIqgMA48rJ5 .icon-shape .label{text-anchor:middle;}#mermaid-svg-rEUhbyIqgMA48rJ5 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-rEUhbyIqgMA48rJ5 .rough-node .label,#mermaid-svg-rEUhbyIqgMA48rJ5 .node .label,#mermaid-svg-rEUhbyIqgMA48rJ5 .image-shape .label,#mermaid-svg-rEUhbyIqgMA48rJ5 .icon-shape .label{text-align:center;}#mermaid-svg-rEUhbyIqgMA48rJ5 .node.clickable{cursor:pointer;}#mermaid-svg-rEUhbyIqgMA48rJ5 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-rEUhbyIqgMA48rJ5 .arrowheadPath{fill:#333333;}#mermaid-svg-rEUhbyIqgMA48rJ5 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-rEUhbyIqgMA48rJ5 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-rEUhbyIqgMA48rJ5 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rEUhbyIqgMA48rJ5 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-rEUhbyIqgMA48rJ5 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rEUhbyIqgMA48rJ5 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-rEUhbyIqgMA48rJ5 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-rEUhbyIqgMA48rJ5 .cluster text{fill:#333;}#mermaid-svg-rEUhbyIqgMA48rJ5 .cluster span{color:#333;}#mermaid-svg-rEUhbyIqgMA48rJ5 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-rEUhbyIqgMA48rJ5 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-rEUhbyIqgMA48rJ5 rect.text{fill:none;stroke-width:0;}#mermaid-svg-rEUhbyIqgMA48rJ5 .icon-shape,#mermaid-svg-rEUhbyIqgMA48rJ5 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rEUhbyIqgMA48rJ5 .icon-shape p,#mermaid-svg-rEUhbyIqgMA48rJ5 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-rEUhbyIqgMA48rJ5 .icon-shape .label rect,#mermaid-svg-rEUhbyIqgMA48rJ5 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rEUhbyIqgMA48rJ5 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-rEUhbyIqgMA48rJ5 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-rEUhbyIqgMA48rJ5 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Ptr
Interface
reflect.ValueOf(x)
v.Type() → *rtype
v.Kind() → Kind枚举
v.Interface() → any
v.Elem() → 解引用
v.Field(i) → 字段
v.Call(args) → 调用
v.Set(x) → 赋值
指向的值
具体值
结构体字段Value
\[\]Value 返回值
修改后的值
三、errors --- 错误处理
3.1 errors.New
go
func New(text string) error {
return &errorString{text}
}
type errorString struct {
s string
}
3.2 错误链 (Unwrap)
go
// 单层 Unwrap
type wrapError struct {
msg string
err error
}
func (e *wrapError) Unwrap() error { return e.err }
// 多层 Unwrap (Go 1.20+)
type joinError struct {
errs []error
}
func (e *joinError) Unwrap() []error { return e.errs }
3.3 Is/As --- 错误树遍历
go
func Is(err, target error) bool {
// 深度优先遍历错误树
for {
if err == target { return true }
// 尝试 Unwrap() error
if unwrapper, ok := err.(interface{ Unwrap() error }); ok {
err = unwrapper.Unwrap()
continue
}
// 尝试 Unwrap() []error
if multi, ok := err.(interface{ Unwrap() []error }); ok {
for _, e := range multi.Unwrap() {
if Is(e, target) { return true }
}
}
return false
}
}
错误树遍历
#mermaid-svg-p05xMJ7Zxf6bGG4p{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-p05xMJ7Zxf6bGG4p .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-p05xMJ7Zxf6bGG4p .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-p05xMJ7Zxf6bGG4p .error-icon{fill:#552222;}#mermaid-svg-p05xMJ7Zxf6bGG4p .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-p05xMJ7Zxf6bGG4p .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-p05xMJ7Zxf6bGG4p .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-p05xMJ7Zxf6bGG4p .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-p05xMJ7Zxf6bGG4p .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-p05xMJ7Zxf6bGG4p .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-p05xMJ7Zxf6bGG4p .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-p05xMJ7Zxf6bGG4p .marker{fill:#333333;stroke:#333333;}#mermaid-svg-p05xMJ7Zxf6bGG4p .marker.cross{stroke:#333333;}#mermaid-svg-p05xMJ7Zxf6bGG4p svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-p05xMJ7Zxf6bGG4p p{margin:0;}#mermaid-svg-p05xMJ7Zxf6bGG4p .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-p05xMJ7Zxf6bGG4p .cluster-label text{fill:#333;}#mermaid-svg-p05xMJ7Zxf6bGG4p .cluster-label span{color:#333;}#mermaid-svg-p05xMJ7Zxf6bGG4p .cluster-label span p{background-color:transparent;}#mermaid-svg-p05xMJ7Zxf6bGG4p .label text,#mermaid-svg-p05xMJ7Zxf6bGG4p span{fill:#333;color:#333;}#mermaid-svg-p05xMJ7Zxf6bGG4p .node rect,#mermaid-svg-p05xMJ7Zxf6bGG4p .node circle,#mermaid-svg-p05xMJ7Zxf6bGG4p .node ellipse,#mermaid-svg-p05xMJ7Zxf6bGG4p .node polygon,#mermaid-svg-p05xMJ7Zxf6bGG4p .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-p05xMJ7Zxf6bGG4p .rough-node .label text,#mermaid-svg-p05xMJ7Zxf6bGG4p .node .label text,#mermaid-svg-p05xMJ7Zxf6bGG4p .image-shape .label,#mermaid-svg-p05xMJ7Zxf6bGG4p .icon-shape .label{text-anchor:middle;}#mermaid-svg-p05xMJ7Zxf6bGG4p .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-p05xMJ7Zxf6bGG4p .rough-node .label,#mermaid-svg-p05xMJ7Zxf6bGG4p .node .label,#mermaid-svg-p05xMJ7Zxf6bGG4p .image-shape .label,#mermaid-svg-p05xMJ7Zxf6bGG4p .icon-shape .label{text-align:center;}#mermaid-svg-p05xMJ7Zxf6bGG4p .node.clickable{cursor:pointer;}#mermaid-svg-p05xMJ7Zxf6bGG4p .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-p05xMJ7Zxf6bGG4p .arrowheadPath{fill:#333333;}#mermaid-svg-p05xMJ7Zxf6bGG4p .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-p05xMJ7Zxf6bGG4p .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-p05xMJ7Zxf6bGG4p .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-p05xMJ7Zxf6bGG4p .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-p05xMJ7Zxf6bGG4p .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-p05xMJ7Zxf6bGG4p .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-p05xMJ7Zxf6bGG4p .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-p05xMJ7Zxf6bGG4p .cluster text{fill:#333;}#mermaid-svg-p05xMJ7Zxf6bGG4p .cluster span{color:#333;}#mermaid-svg-p05xMJ7Zxf6bGG4p div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-p05xMJ7Zxf6bGG4p .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-p05xMJ7Zxf6bGG4p rect.text{fill:none;stroke-width:0;}#mermaid-svg-p05xMJ7Zxf6bGG4p .icon-shape,#mermaid-svg-p05xMJ7Zxf6bGG4p .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-p05xMJ7Zxf6bGG4p .icon-shape p,#mermaid-svg-p05xMJ7Zxf6bGG4p .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-p05xMJ7Zxf6bGG4p .icon-shape .label rect,#mermaid-svg-p05xMJ7Zxf6bGG4p .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-p05xMJ7Zxf6bGG4p .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-p05xMJ7Zxf6bGG4p .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-p05xMJ7Zxf6bGG4p :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} .Unwrap()
.Unwrap()
fmt.Errorf('wrap1: %w', err1)
err1 = fmt.Errorf('wrap2: %w', err2)
err2 = errors.New('base')
errors.Is(root, err2) → true
errors.Is(root, err1) → true
四、设计模式总结
| # | 模式 | 体现 |
|---|---|---|
| 1 | 组合模式 | context: cancelCtx/timerCtx/valueCtx 嵌套 |
| 2 | 观察者模式 | cancelCtx → children map 取消通知 |
| 3 | 闭 channel 信号 | close(done) 广播取消 |
| 4 | 递归查找 | valueCtx.Value 链式查找 |
| 5 | 延迟初始化 | cancelCtx.done 延迟创建 |
| 6 | 接口多态 | Context 接口 4 种实现 |
| 7 | 类型擦除 | reflect.Type 对 Go 类型系统的抽象 |
| 8 | 位图标志 | Value.flag kind+flags 编码 |
| 9 | 安全封装 | Value 隐藏 unsafe.Pointer |
| 10 | 错误链 | Unwrap() 单/多 层遍历 |
| 11 | 深度优先 | errors.Is/As 树遍历 |
| 12 | Cause 语义 | WithCancelCause/Cause 记录原因 |