一、介绍

reflect包主要用来检查interface{}类型的类型type和值value
我们可以用

reflect.TypeOf()  得到  reflect.Type 反射接口
reflect.ValueOf() 得到  reflect.Value 反射值

在reflect包里,struct里的字段使用 StructField结构体表示

// A StructField describes struct 结构体的 field 字段 .
type StructField struct {
    // Name is the field name.
    Name string
    // PkgPath is the package path that qualifies a lower case (unexported)
    PkgPath string

    Type      Type      // field type
    Tag       StructTag // field tag string
    Offset    uintptr   // offset within struct, in bytes
    Index     []int     // index sequence for Type.FieldByIndex
    Anonymous bool      // is an embedded field
}

二、reflect.Type

在这里我们以struct举例:打开源码 src/reflect/type.go

type Type interface {
    //通用的3个函数
    //返回kind,基础类型,Struct,Bool,Int,Int8,Array,Chan,Func,Map...
    Kind() Kind
    //返回结构体名称
    Name() string
    //返回包路径
    PkgPath() string

 
    //struct相关的3个重要方法,可以看到如果不是struct的话,会报错
    // Field returns a struct type's i'th field.
    // It panics if the type's Kind is not Struct.
    // It panics if i is not in the range [0, NumField()).
    Field(i int) StructField

    // FieldByName returns the struct field with the given name
    // and a boolean indicating if the field was found.
    FieldByName(name string) (StructField, bool)

    // NumField returns a struct type's field count.
    // It panics if the type's Kind is not Struct.
    NumField() int
}

本文主要截取了reflect.Type的6个方法以及StructField结构体的field字段

  1. 通用的方法 Kind(),Name(),PkgPath()
  2. struct相关方法 NumField(),FieldByName(),Field()
  3. StructField结构体,用来描述struct结构体的字段field

我们先看一个结构体

type Person struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

然后反射获得type类型,打印一下,上面的6个方法:

func TestStructType(t *testing.T) {
    p := Person{
        Name: "hisheng",
        Age:  100,
    }
    typeP := reflect.TypeOf(p)
    t.Log(typeP.Kind())    //struct
    t.Log(typeP.Name())    //Person
    t.Log(typeP.PkgPath()) //github.com/hisheng/dataStructure/reflect_

    t.Log(typeP.NumField())         //2个结构体field字段
    t.Log(typeP.Field(0))           //第0个结构体字段,StructField类型  {Name  string json:"name" 0 [0] false}
    t.Log(typeP.FieldByName("Age")) //获取Age StructField类型 {Age  int json:"age" 16 [1] false} true
}

二、reflect.Value

打开源码 src/reflect/value.go 或者用 go doc reflect.value 命令
可以了解到主要由一个reflect.Value结构体以及重要的几个方法组成。

type Value struct {
    // typ holds the type of the value represented by a Value.
    typ *rtype

    // Pointer-valued data or, if flagIndir is set, pointer to data.
    // Valid when either flagIndir is set or typ.pointers() is true.
    ptr unsafe.Pointer

    // flag holds metadata about the value.
    flag
}

主要的方法有:

func (v Value) Kind() Kind
func (v Value) NumField() int
func (v Value) Field(i int) Value
func (v Value) FieldByName(name string) Value

我们这里使用一下:

func TestStructValue(t *testing.T) {
    p := Person{
        Name: "hisheng",
        Age:  100,
    }
    valueP := reflect.ValueOf(p)
    t.Log(valueP.Kind()) //struct

    t.Log(valueP.NumField())         //2
    t.Log(valueP.Field(0))           // 返回reflect.Value 打印 hisheng
    t.Log(valueP.FieldByName("Age")) //返回reflect.Value 打印 100
}

三、StructField 结构体字段

package reflect_

import (
    "reflect"
    "testing"
)

type Person struct {
    Name     string `json:"name"`
    Age      int    `json:"age"`
    password []byte
    Address  Address `json:"address"`
}
type Address struct {
    Country string `json:"country"`
    City    string `json:"city"`
}
//遍历struct
func TestStructField(t *testing.T) {
    p := Person{
        Name:     "hisheng",
        Age:      100,
        password: []byte("pwd"),
        Address:  Address{Country: "china", City: "shanghai"},
    }
    typeP := reflect.TypeOf(p)
    if typeP.Kind() == reflect.Struct {
        //遍历struct
        for i := 0; i < typeP.NumField(); i++ {
            structField := typeP.Field(i)
            t.Logf("%s %s %s", structField.Name, structField.Type, structField.Tag)
        }
    }
}

输出如下:

Name string json:"name"
Age int json:"age"
password []uint8 
Address reflect_.Address json:"address"

可以发现,我们打印出了 Person 结构体的 每一个field字段。

四、StructTag 结构体字段tag

Struct Tag是存在于Struct字段下面成员的附加属性,
它的定义永远都是以key-value的形式出现的,多个定义的情况下以空格分割

image.png

package reflect_

import (
    "reflect"
    "testing"
)

type Person struct {
    Name     string `json:"name,omitempty" xml:"name_x"`
    Age      int    `json:"age"`
}

func TestStructFieldTag(t *testing.T) {
    p := Person{Name: "hisheng"}
    typeP := reflect.TypeOf(p)
    if typeP.Kind() == reflect.Struct {
        structField := typeP.Field(0) // 对应Name这个 字段
        var structFieldTag reflect.StructTag = structField.Tag
        t.Log(structFieldTag)         //json:"name,omitempty" xml:"name_x"
        t.Log(structFieldTag.Get("json")) //name,omitempty
        t.Log(structFieldTag.Get("xml"))  //name_x
    }
}

好文学习补充:
深度剖析Reflect + 实战案例
Go 每日一库之 reflect

谢谢您的观看,欢迎关注我的公众号。

image.png


海生
104 声望32 粉丝

与黑夜里,追求那一抹萤火。