Go语言源码剖析——类型系统与反射概览

模块概述

职责定义

反射(Reflection)是Go语言在运行时检查和操作类型、值信息的能力。reflect包提供了完整的反射API,允许程序在运行时:

  • 检查任意值的类型信息
  • 读取/修改变量的值
  • 调用方法和函数
  • 动态创建对象

反射建立在Go的类型系统之上,核心包括runtime的_type系统和reflect包的Type/Value API。

三定律

Rob Pike总结的反射三定律:

  1. Reflection goes from interface value to reflection object.
    反射从接口值到反射对象。

    v := reflect.ValueOf(x)  // 从接口{}到Value
    t := reflect.TypeOf(x)   // 从接口{}到Type
    
  2. Reflection goes from reflection object to interface value.
    反射从反射对象到接口值。

    y := v.Interface().(T)  // 从Value到具体类型
    
  3. To modify a reflection object, the value must be settable.
    要修改反射对象,值必须可设置。

    v := reflect.ValueOf(&x).Elem()  // 取地址才可修改
    v.SetInt(42)
    

核心概念

Type - 类型信息

  • 描述类型的结构:大小、对齐、方法集等
  • 不可修改的静态信息
  • 编译器生成,运行时使用

Value - 值信息

  • 封装了具体值和类型
  • 提供读写操作
  • 支持方法调用

Kind - 类型种类

  • Go的27种基础类型:int、string、struct、slice等
  • Type的底层分类
  • 决定了可用的操作

模块架构图

flowchart TB
    subgraph "类型系统层次 Type System Layers"
        COMPILER[编译器<br/>cmd/compile]
        RUNTIME[运行时类型<br/>runtime._type]
        REFLECT[反射包<br/>reflect.Type/Value]
        USER[用户代码<br/>reflect API]
        
        COMPILER -->|生成类型元数据| RUNTIME
        RUNTIME -->|提供底层类型| REFLECT
        REFLECT -->|暴露API| USER
    end
    
    subgraph "runtime类型系统"
        TYPE[_type 基础类型描述符<br/>所有类型的公共部分]
        
        subgraph "特化类型"
            ARRAYTYPE[arraytype 数组]
            CHANTYPE[chantype 通道]
            FUNCTYPE[functype 函数]
            MAPTYPE[maptype 映射]
            PTRTYPE[ptrtype 指针]
            SLICETYPE[slicetype 切片]
            STRUCTTYPE[structtype 结构体]
            INTERFACETYPE[interfacetype 接口]
        end
        
        TYPE --> ARRAYTYPE
        TYPE --> CHANTYPE
        TYPE --> FUNCTYPE
        TYPE --> MAPTYPE
        TYPE --> PTRTYPE
        TYPE --> SLICETYPE
        TYPE --> STRUCTTYPE
        TYPE --> INTERFACETYPE
    end
    
    subgraph "_type 基础描述符"
        SIZE[Size 类型大小]
        PTRDATA[PtrBytes 含指针的字节数]
        HASH[Hash 类型哈希]
        TFLAG[TFlag 类型标志]
        ALIGN[Align_ 对齐]
        KIND[Kind_ 类型种类]
        
        TYPE --> SIZE
        TYPE --> PTRDATA
        TYPE --> HASH
    end
    
    subgraph "reflect.Type 接口"
        RTYPE[rtype<br/>reflect的_type包装]
        TYPEMETHODS[Type接口方法<br/>Name/Kind/Size等]
        KINDSPECIFIC[种类特定方法<br/>Field/Elem/Key等]
        
        RTYPE -.实现.-> TYPEMETHODS
        RTYPE -.实现.-> KINDSPECIFIC
    end
    
    subgraph "reflect.Value 结构"
        VTYP[typ_ *abi.Type<br/>类型指针]
        VPTR[ptr unsafe.Pointer<br/>数据指针]
        VFLAG[flag uintptr<br/>标志位]
        
        subgraph "flag标志位"
            FKIND[低5位:Kind]
            FRO[只读标志]
            FINDIR[间接标志]
            FADDR[可寻址标志]
            FMETHOD[方法标志]
        end
        
        VFLAG --> FKIND
        VFLAG --> FRO
        VFLAG --> FINDIR
    end
    
    subgraph "核心操作"
        subgraph "类型操作"
            TYPEOF[TypeOf()<br/>获取类型]
            IMPLEMENTS[Implements()<br/>接口检查]
            ASSIGNABLE[AssignableTo()<br/>赋值检查]
        end
        
        subgraph "值操作"
            VALUEOF[ValueOf()<br/>获取值]
            SET[Set系列<br/>修改值]
            CALL[Call()<br/>调用方法]
            INTERFACE[Interface()<br/>转接口]
        end
        
        subgraph "类型转换"
            CONVERT[Convert()<br/>类型转换]
            ZERO[Zero()<br/>零值]
            NEW[New()<br/>创建实例]
            MAKEFUNC[MakeFunc()<br/>动态函数]
        end
    end
    
    RUNTIME -.提供类型.-> RTYPE
    RTYPE --> TYPEOF
    RTYPE --> IMPLEMENTS
    
    VTYP --> RTYPE
    VPTR --> SET
    VFLAG --> SET

架构图说明

runtime._type - 运行时类型基础

所有Go类型在运行时都有对应的_type描述符,由编译器生成。

type _type struct {
    Size_       uintptr  // 类型大小(字节)
    PtrBytes    uintptr  // 前PtrBytes字节可能包含指针
    Hash        uint32   // 类型哈希,用于map和type switch
    TFlag       tflag    // 类型标志
    Align_      uint8    // 变量对齐
    FieldAlign_ uint8    // 结构体字段对齐
    Kind_       uint8    // 类型种类(低5位)
    
    Equal       func(unsafe.Pointer, unsafe.Pointer) bool  // 相等函数
    GCData      *byte    // GC类型数据
    Str         nameOff  // 类型名称偏移
    PtrToThis   typeOff  // *T的类型偏移
}

关键字段

  • Size_:类型占用内存大小
  • PtrBytes:前N字节可能包含指针,GC扫描用
  • Hash:类型的哈希值,用于快速比较
  • Kind_:27种基础类型之一
  • Equal:两个值是否相等的函数指针

特化类型

不同Kind的类型有额外的元数据:

// 数组类型
type arraytype struct {
    typ   _type  // 基础部分
    elem  *_type // 元素类型
    slice *_type // []T的类型
    len   uintptr // 数组长度
}

// 切片类型
type slicetype struct {
    typ  _type
    elem *_type  // 元素类型
}

// 结构体类型
type structtype struct {
    typ     _type
    pkgPath name
    fields  []structfield  // 字段列表
}

type structfield struct {
    name       name    // 字段名
    typ        *_type  // 字段类型
    offsetAnon uintptr // 偏移+匿名标志
}

// 函数类型
type functype struct {
    typ      _type
    inCount  uint16  // 输入参数数量
    outCount uint16  // 输出参数数量(高位表示变参)
}

// 接口类型
type interfacetype struct {
    typ     _type
    pkgPath name
    methods []imethod  // 方法列表
}

// 映射类型
type maptype struct {
    typ           _type
    key           *_type
    elem          *_type
    bucket        *_type  // 桶类型
    hasher        func(unsafe.Pointer, uintptr) uintptr
    keysize       uint8
    valuesize     uint8
    bucketsize    uint16
    flags         uint32
}

reflect.Type - 类型接口

reflect.Type是类型信息的公共接口,rtype是其内部实现。

// reflect包中的实现
type rtype struct {
    t abi.Type  // 即runtime._type
}

// rtype实现了Type接口
func (t *rtype) Size() uintptr       { return t.t.Size_ }
func (t *rtype) Kind() Kind          { return Kind(t.t.Kind_ & kindMask) }
func (t *rtype) String() string      { return t.t.String() }
func (t *rtype) NumMethod() int      { ... }

Type接口主要方法

type Type interface {
    // 通用方法
    Name() string       // 类型名称
    Kind() Kind         // 类型种类
    Size() uintptr      // 大小
    Align() int         // 对齐
    NumMethod() int     // 方法数量
    Method(int) Method  // 第i个方法
    
    // 类型关系
    Implements(Type) bool      // 是否实现接口
    AssignableTo(Type) bool    // 是否可赋值
    ConvertibleTo(Type) bool   // 是否可转换
    Comparable() bool          // 是否可比较
    
    // 种类特定方法(仅特定Kind可用)
    Elem() Type              // Array/Chan/Map/Pointer/Slice的元素类型
    Key() Type               // Map的键类型
    Len() int                // Array的长度
    NumField() int           // Struct的字段数
    Field(int) StructField   // Struct的第i个字段
    NumIn() int              // Func的输入参数数
    In(int) Type             // Func的第i个输入参数类型
    NumOut() int             // Func的输出参数数
    Out(int) Type            // Func的第i个输出参数类型
}

reflect.Value - 值封装

Value封装了值的类型、数据和元数据。

type Value struct {
    typ_ *abi.Type      // 类型指针
    ptr  unsafe.Pointer // 数据指针
    flag               // 标志位
}

type flag uintptr

const (
    flagKindMask    flag = 1<<5 - 1  // 低5位:Kind
    flagStickyRO    flag = 1 << 5    // 通过非导出字段获得,只读
    flagEmbedRO     flag = 1 << 6    // 通过嵌入字段获得,只读
    flagIndir       flag = 1 << 7    // ptr是指向数据的指针
    flagAddr        flag = 1 << 8    // 可寻址
    flagMethod      flag = 1 << 9    // 是方法值
)

flag编码

|---------- 高位 ----------|-- 10 --|-- 9 --|-- 8 --|-- 7 --|-- 6 --|-- 5 --|-- 低5位 --|
|    方法编号(方法值用)     |flagMethod|flagAddr|flagIndir|flagEmbedRO|flagStickyRO|  Kind  |

ptr字段的含义

  • flagIndir=0:ptr直接是值(用于指针、uintptr等)
  • flagIndir=1:ptr指向值(用于结构体、数组等)

可设置性(Settable)

v := reflect.ValueOf(x)         // 不可设置(x的副本)
v := reflect.ValueOf(&x).Elem() // 可设置(通过指针)

条件:

  1. flagAddr=1(可寻址)
  2. flagRO=0(非只读,即非通过非导出字段获得)

核心算法详解

1. TypeOf() - 获取类型

入口函数

func TypeOf(i interface{}) Type {
    eface := *(*emptyInterface)(unsafe.Pointer(&i))
    return toType(eface.typ)
}

type emptyInterface struct {
    typ  *rtype
    word unsafe.Pointer
}

算法逻辑

  1. interface{}转换为内部的eface结构
  2. 提取_type指针
  3. 包装为rtype并返回

零拷贝:无需复制数据,只取类型指针。

2. ValueOf() - 获取值

入口函数

func ValueOf(i interface{}) Value {
    if i == nil {
        return Value{}  // 零值
    }
    
    return unpackEface(i)
}

func unpackEface(i interface{}) Value {
    e := (*emptyInterface)(unsafe.Pointer(&i))
    t := e.typ
    if t == nil {
        return Value{}
    }
    f := flag(t.Kind())
    if t.IfaceIndir() {
        f |= flagIndir
    }
    return Value{t, e.word, f}
}

算法步骤

  1. 检查nil(返回零值)
  2. 解包interface{}eface
  3. 提取类型和数据指针
  4. 设置flag:
    • 低5位:Kind
    • flagIndir:根据类型决定
  5. 返回Value{typ, ptr, flag}

3. Value.Set() - 修改值

核心代码

func (v Value) Set(x Value) {
    v.mustBeAssignable()  // 检查可设置性
    x.mustBeExported()    // 检查x可导出
    
    var target unsafe.Pointer
    if v.kind() == Interface {
        target = v.ptr
    }
    
    // 类型检查
    x = x.assignTo("reflect.Set", v.typ_, target)
    
    // 复制值
    if v.flag&flagIndir != 0 {
        // v.ptr指向数据
        typedmemmove(v.typ_, v.ptr, x.ptr)
    } else {
        // v.ptr就是数据
        *(*unsafe.Pointer)(v.ptr) = x.ptr
    }
}

前置检查

func (v Value) mustBeAssignable() {
    if !v.CanSet() {
        if v.flag == 0 {
            panic(&ValueError{"reflect.Value.Set", Invalid})
        }
        if v.flag&flagRO != 0 {
            panic("reflect: cannot set using value obtained using unexported field")
        }
        panic("reflect: cannot set value using unaddressable value")
    }
}

func (v Value) CanSet() bool {
    return v.flag&flagAddr != 0 && v.flag&flagRO == 0
}

类型赋值检查

func (v Value) assignTo(context string, dst *abi.Type, target unsafe.Pointer) Value {
    // 相同类型
    if v.typ_ == dst {
        v.typ_ = dst
        fl := v.flag&(flagAddr|flagIndir) | flag(dst.Kind())
        return Value{dst, v.ptr, fl}
    }
    
    // 类型可赋值
    if directlyAssignable(dst, v.typ_) {
        // 实现细节...
    }
    
    // 接口断言
    if dst.Kind() == abi.Interface {
        if v.typ_.Implements(dst) {
            // 转换为接口...
        }
    }
    
    panic(context + ": value of type " + v.typ_.String() + 
          " is not assignable to type " + dst.String())
}

4. Value.Call() - 调用方法/函数

核心代码

func (v Value) Call(in []Value) []Value {
    v.mustBe(Func)
    v.mustBeExported()
    return v.call("Call", in)
}

func (v Value) call(op string, in []Value) []Value {
    t := (*funcType)(unsafe.Pointer(v.typ_))
    
    // 检查参数数量
    n := t.NumIn()
    if len(in) < n {
        panic("reflect: Call with too few input arguments")
    }
    if len(in) > n && !t.IsVariadic() {
        panic("reflect: Call with too many input arguments")
    }
    
    // 参数类型检查和转换
    for i := 0; i < n; i++ {
        var xt *abi.Type
        if t.IsVariadic() && i == n-1 {
            xt = t.In(i).Elem().common()
        } else {
            xt = t.In(i).common()
        }
        
        in[i] = in[i].assignTo("reflect.Value.Call", xt, nil)
    }
    
    // 调用
    return v.callReflect(op, in)
}

参数marshalling

func (v Value) callReflect(op string, in []Value) []Value {
    fn := v.pointer()
    t := (*funcType)(unsafe.Pointer(v.typ_))
    
    // 分配参数内存
    frameSize := t.frameSize()
    args := unsafe_New(frameType)
    
    // 复制输入参数
    off := 0
    for i, arg := range in {
        argType := t.In(i)
        off = align(off, argType.Align())
        
        argPtr := add(args, off)
        if arg.flag&flagIndir != 0 {
            typedmemmove(argType, argPtr, arg.ptr)
        } else {
            *(*unsafe.Pointer)(argPtr) = arg.ptr
        }
        off += argType.Size()
    }
    
    // 调用函数
    call(frametype, fn, args, uint32(frametype.size), uint32(retOffset))
    
    // 提取返回值
    out := make([]Value, t.NumOut())
    off = retOffset
    for i := 0; i < t.NumOut(); i++ {
        outType := t.Out(i)
        off = align(off, outType.Align())
        
        outPtr := add(args, off)
        out[i] = Value{outType, outPtr, flag(outType.Kind()) | flagIndir}
        off += outType.Size()
    }
    
    return out
}

5. Type.Implements() - 接口检查

核心代码

func (t *rtype) Implements(u Type) bool {
    if u == nil {
        panic("reflect: nil type passed to Type.Implements")
    }
    
    if u.Kind() != Interface {
        panic("reflect: non-interface type passed to Type.Implements")
    }
    
    return implements(u.(*rtype), t)
}

func implements(T, V *rtype) bool {
    if T.Kind() != Interface {
        return false
    }
    
    t := (*interfaceType)(unsafe.Pointer(T))
    if len(t.Methods) == 0 {
        return true  // 空接口
    }
    
    // V必须有方法
    if V.Kind() == Interface {
        v := (*interfaceType)(unsafe.Pointer(V))
        i := 0
        for j := 0; j < len(v.Methods); j++ {
            tm := &t.Methods[i]
            vm := &v.Methods[j]
            
            if vm.Name == tm.Name && vm.Typ == tm.Typ {
                i++
                if i >= len(t.Methods) {
                    return true  // 所有方法都找到
                }
            }
        }
        return false
    }
    
    v := V.uncommon()
    if v == nil {
        return false  // 没有方法
    }
    
    // 双指针遍历检查方法
    i := 0
    vmethods := v.Methods()
    for j := 0; j < int(v.Mcount); j++ {
        tm := &t.Methods[i]
        vm := &vmethods[j]
        
        if vm.Name() == tm.Name.Name() && vm.Typ == tm.Typ {
            i++
            if i >= len(t.Methods) {
                return true
            }
        }
    }
    return false
}

算法逻辑

  1. 检查T是接口类型
  2. 空接口:直接返回true
  3. 接口→接口:双指针遍历方法列表(都已排序)
  4. 具体类型→接口:遍历类型的方法,查找接口的所有方法
  5. 所有接口方法都找到:返回true

6. MakeFunc() - 动态函数

核心代码

func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
    if typ.Kind() != Func {
        panic("reflect: call of MakeFunc with non-Func type")
    }
    
    t := typ.common()
    ftyp := (*funcType)(unsafe.Pointer(t))
    
    // 创建函数闭包
    code := abi.FuncPCABI0(makeFuncStub)
    impl := &makeFuncImpl{
        code: code,
        typ:  ftyp,
        fn:   fn,
    }
    
    return Value{t, unsafe.Pointer(impl), flag(Func)}
}

type makeFuncImpl struct {
    code uintptr
    typ  *funcType
    fn   func([]Value) []Value
}

调用流程

用户调用 → makeFuncStub(汇编) → callReflect → 用户fn → 构造返回值

汇编桩(arch-specific)

TEXT ·makeFuncStub(SB),NOSPLIT,$0
    MOVQ DX, 0(SP)          // 保存闭包指针
    CALL ·callReflect(SB)   // 调用Go函数
    RET

性能考虑

1. 反射开销

性能对比(相对于直接调用)

直接调用:         1x
接口调用:         1.2x
反射TypeOf:       10x
反射ValueOf:      15x
反射Set:          20x
反射Call:         50x

2. 优化策略

缓存Type

// 不推荐:重复获取Type
for i := 0; i < n; i++ {
    t := reflect.TypeOf(x)  // 每次都调用
    // ...
}

// 推荐:缓存Type
t := reflect.TypeOf(x)
for i := 0; i < n; i++ {
    // 使用t
}

避免Value.Interface()转换

// 不推荐:频繁转换
v := reflect.ValueOf(x)
for i := 0; i < n; i++ {
    y := v.Interface().(int)  // 每次都转换
}

// 推荐:直接使用Value方法
v := reflect.ValueOf(x)
for i := 0; i < n; i++ {
    y := v.Int()  // 直接取值
}

批量操作

// 不推荐:逐个字段操作
v := reflect.ValueOf(&s).Elem()
for i := 0; i < v.NumField(); i++ {
    f := v.Field(i)
    // 单独处理每个字段
}

// 推荐:使用FieldByIndex批量
type访问
v := reflect.ValueOf(&s).Elem()
indices := [][]int{{0}, {1}, {2}}
values := make([]reflect.Value, len(indices))
for i, idx := range indices {
    values[i] = v.FieldByIndex(idx)
}

3. 内存分配

零拷贝方法

  • TypeOf():仅取类型指针
  • Value.Kind():读取flag
  • Value.Type():返回rtype(无分配)

有分配的方法

  • ValueOf(x):小值优化,大对象分配
  • Value.Interface():转换为interface{}(eface分配)
  • MakeSlice/MakeMap/MakeChan:分配底层数据结构

反射API最佳实践

1. 类型检查

func process(i interface{}) {
    v := reflect.ValueOf(i)
    
    // 检查Kind
    switch v.Kind() {
    case reflect.Int, reflect.Int64:
        n := v.Int()
        // 处理整数
    case reflect.String:
        s := v.String()
        // 处理字符串
    case reflect.Struct:
        // 遍历字段
        for i := 0; i < v.NumField(); i++ {
            f := v.Field(i)
            // 处理字段
        }
    default:
        panic("unsupported type")
    }
}

2. 结构体遍历

func inspectStruct(s interface{}) {
    v := reflect.ValueOf(s)
    if v.Kind() == reflect.Ptr {
        v = v.Elem()
    }
    if v.Kind() != reflect.Struct {
        panic("not a struct")
    }
    
    t := v.Type()
    for i := 0; i < v.NumField(); i++ {
        field := t.Field(i)
        value := v.Field(i)
        
        fmt.Printf("%s: %v (type: %s, tag: %s)\n",
            field.Name,
            value.Interface(),
            field.Type,
            field.Tag.Get("json"))
    }
}

3. 安全的Set操作

func safeSet(ptr interface{}, value interface{}) error {
    v := reflect.ValueOf(ptr)
    
    // 必须是指针
    if v.Kind() != reflect.Ptr {
        return errors.New("not a pointer")
    }
    
    v = v.Elem()
    
    // 检查可设置性
    if !v.CanSet() {
        return errors.New("cannot set")
    }
    
    newVal := reflect.ValueOf(value)
    
    // 类型检查
    if !newVal.Type().AssignableTo(v.Type()) {
        return fmt.Errorf("cannot assign %s to %s",
            newVal.Type(), v.Type())
    }
    
    v.Set(newVal)
    return nil
}

4. 方法调用

func callMethod(obj interface{}, methodName string, args ...interface{}) ([]interface{}, error) {
    v := reflect.ValueOf(obj)
    m := v.MethodByName(methodName)
    
    if !m.IsValid() {
        return nil, fmt.Errorf("method %s not found", methodName)
    }
    
    // 构造参数
    in := make([]reflect.Value, len(args))
    for i, arg := range args {
        in[i] = reflect.ValueOf(arg)
    }
    
    // 调用
    results := m.Call(in)
    
    // 提取返回值
    out := make([]interface{}, len(results))
    for i, r := range results {
        out[i] = r.Interface()
    }
    
    return out, nil
}

5. 深度拷贝

func deepCopy(src interface{}) interface{} {
    v := reflect.ValueOf(src)
    return deepCopyValue(v).Interface()
}

func deepCopyValue(v reflect.Value) reflect.Value {
    switch v.Kind() {
    case reflect.Ptr:
        if v.IsNil() {
            return v
        }
        newVal := reflect.New(v.Elem().Type())
        newVal.Elem().Set(deepCopyValue(v.Elem()))
        return newVal
        
    case reflect.Struct:
        newVal := reflect.New(v.Type()).Elem()
        for i := 0; i < v.NumField(); i++ {
            newVal.Field(i).Set(deepCopyValue(v.Field(i)))
        }
        return newVal
        
    case reflect.Slice:
        if v.IsNil() {
            return v
        }
        newVal := reflect.MakeSlice(v.Type(), v.Len(), v.Cap())
        for i := 0; i < v.Len(); i++ {
            newVal.Index(i).Set(deepCopyValue(v.Index(i)))
        }
        return newVal
        
    case reflect.Map:
        if v.IsNil() {
            return v
        }
        newVal := reflect.MakeMap(v.Type())
        for _, key := range v.MapKeys() {
            newVal.SetMapIndex(deepCopyValue(key), deepCopyValue(v.MapIndex(key)))
        }
        return newVal
        
    default:
        return v
    }
}

典型应用场景

1. JSON序列化/反序列化

// encoding/json使用反射遍历结构体
func Marshal(v interface{}) ([]byte, error) {
    val := reflect.ValueOf(v)
    return marshalValue(val)
}

func marshalValue(v reflect.Value) ([]byte, error) {
    switch v.Kind() {
    case reflect.Struct:
        // 遍历字段,读取tag,序列化每个字段
    case reflect.Map:
        // 遍历键值对,序列化
    // ...
    }
}

2. ORM框架

// gorm使用反射构造SQL和映射结果
type User struct {
    ID   int    `gorm:"primary_key"`
    Name string `gorm:"column:user_name"`
}

func (db *DB) Find(dest interface{}) error {
    v := reflect.ValueOf(dest).Elem()
    t := v.Type()
    
    // 从struct tag构造SQL
    // SELECT * FROM users ...
    
    // 映射结果到字段
    for i := 0; i < v.NumField(); i++ {
        field := v.Field(i)
        column := t.Field(i).Tag.Get("gorm")
        // 从row读取column,设置到field
    }
}

3. 依赖注入

// 根据类型自动注入依赖
func Inject(container map[reflect.Type]interface{}, target interface{}) {
    v := reflect.ValueOf(target).Elem()
    t := v.Type()
    
    for i := 0; i < v.NumField(); i++ {
        field := v.Field(i)
        if !field.CanSet() {
            continue
        }
        
        // 从容器中查找类型匹配的依赖
        if dep, ok := container[field.Type()]; ok {
            field.Set(reflect.ValueOf(dep))
        }
    }
}

4. 测试框架

// testify使用反射比较对象
func Equal(expected, actual interface{}) bool {
    if expected == nil || actual == nil {
        return expected == actual
    }
    
    exp := reflect.ValueOf(expected)
    act := reflect.ValueOf(actual)
    
    return deepEqual(exp, act)
}