当前位置 : 主页 > 网络编程 > 其它编程 >

golangreflect知识集锦

来源:互联网 收集:自由互联 发布时间:2023-07-02
目录反射之结构体tagTypesvsKindsreflect.Typevsreflect.Value2019420补充reflect.Value转原始类型获取类型底层类型遍历字段和 目录 反射之结构体tag Types vs Kinds reflect.Type vs reflect.Value 2019/4/20 补充 ref
目录反射之结构体tagTypesvsKindsreflect.Typevsreflect.Value2019420补充reflect.Value转原始类型获取类型底层类型遍历字段和

目录
  • 反射之结构体tag
  • Types vs Kinds
  • reflect.Type vs reflect.Value
  • 2019/4/20 补充
  • reflect.Value转原始类型
  • 获取类型底层类型
  • 遍历字段和方法
  • 获取值
  • 修改字段的值
  • 动态调用方法

反射之结构体tag

链接

  • 通过v.Field(i).Tag 获取结构体字段的field
  • 通过v.Field(i).Tag.Get("id") 获取结构体字段中的特定信息
  • func(tag StructTag)Lookup(key string)(value string,ok bool)根据 Tag 中的键,查询值是否存在。
  • package mainimport ( "fmt" "reflect")func main() { // 声明一个空结构体 type cat struct { Name string // 带有结构体tag的字段 Type int `json:"type" id:"100"` } // 创建cat的实例 ins := cat{Name: "mimi", Type: 1} // 获取结构体实例的反射类型对象 typeOfCat := reflect.TypeOf(ins) // 遍历结构体所有成员 for i := 0; i Types vs Kinds

    Golang学习 - reflect 包Golang的反射reflect深入理解和示例系列文章

    • kind 指的是golang 内置的类型,如int, int32等,在使用反射时,需要首先理解类型(Type)和种类(Kind)的区别。编程中,使用最多的是类型,但在反射中,当需要区分一个大品种的类型时,就会用到种类(Kind)。例如,需要统一判断类型中的指针时,使用种类(Kind)信息就较为方便。内置类型如下
    内置类型如下 const ( Invalid Kind = iota Bool Int Int8 Int16 Int32 Int64 Uint Uint8 Uint16 Uint32 Uint64 Uintptr Float32 Float64 Complex64 Complex128 Array Chan Func Interface Map Ptr Slice String Struct UnsafePointer)通过reflect.ValueOf(x)或者reflect.TypeOf(x)获取对象后,对其执行v.Kind(), 结果与reflect.TypeOf(x)相同reflect.Kind例子package mainimport ("fmt""reflect")func main() {for _, v := range []interface{}{"hi", 42, func() {}} {switch v := reflect.ValueOf(v); v.Kind() {case reflect.String:fmt.Println(v.String())case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:fmt.Println(v.Int())default:fmt.Printf("unhandled kind %s", v.Kind())}}}hi 42 unhandled kind func
    • type 指的是使用type定义的类型
    type mystruct struct { name string age int}func main() { ms := mystruct{"test", 100} fmt.Println(ms)}

    ms的type为自定义类型mystruct,而kind则为struct

    fmt.Println(reflect.TypeOf(ms))fmt.Println(reflect.ValueOf(ms))// 输出// main.mystruct// {test 100}

    总之: kind是go runtime和compiler为变量分配内存或为函数分配堆栈时是使用的概念,如Int8等。而Type则是Go编程时使用的概念。

    Type is the user defined metadata about data or function in a Go program. Kind is the compiler and runtime defined metadata about data or function in a Go program.Kind is used by the runtime and compiler to allocate the memory layout for a variable or to allocate the stack layout for a function.

    reflect.Type vs reflect.Value

    golang为类型的存储方式为(type, value), type有static type,对应上面的Type,有concrete type,对应上面的Kind。注意只有interface类型才有反射一说。value是实际变量值,type是实际变量的类型。一个interface{}类型的变量包含了2个指针,一个指针指向值的类型【对应concrete type】,另外一个指针指向实际的值【对应value】。

    • reflect.Type直接给到了我们想要的type类型,如float64、int、各种pointer、struct 等等真实的类型
    • reflect.Value直接给到了我们想要的具体的值,如1.2345这个具体数值,或者类似i这个例子打印出结构体的所有字段名以及该结构体的方法。NumField方法获取结构体有多少个字段,然后通过Field方法传递索引的方式,循环获取每一个字段,然后打印出他们的名字。

      同样的对于方法也类似,这里不再赘述。

      获取值

      当我们将一个接口值传递给一个 reflect.ValueOf 函数调用时,此调用返回的是代表着此接口值的动态值的一个 reflect.Value 值。我们必须通过间接的途径获得一个代表一个接口值的 reflect.Value 值golang reflect知识集锦

      // 声明整型变量a并赋初值 var a int = 1024 // 获取变量a的反射值对象 valueOfA := reflect.ValueOf(a) // 获取interface{}类型的值, 通过类型断言转换 var getA int = valueOfA.Interface().(int) // 获取64位的值, 强制类型转换为int类型 var getA2 int = int(valueOfA.Int())

      修改字段的值

      假如我们想在运行中动态的修改某个字段的值有什么办法呢?一种就是我们常规的有提供的方法或者导出的字段可以供我们修改,还有一种是使用反射,这里主要介绍反射。

      func main() { x:=2 v:=reflect.ValueOf(&x) v.Elem().SetInt(100) fmt.Println(x)}因为reflect.ValueOf函数返回的是一份值的拷贝,所以前提是我们是传入要修改变量的地址。其次需要我们调用Elem方法找到这个指针指向的值。最后我们就可以使用SetInt方法修改值了。

      以上有几个重点,才可以保证值可以被修改,Value为我们提供了CanSet方法可以帮助我们判断是否可以修改该对象。

      动态调用方法

      结构体的方法我们不光可以正常的调用,还可以使用反射进行调用。要想反射调用,我们先要获取到需要调用的方法,然后进行传参调用,如下示例:

      func main() { u:=User{"张三",20} v:=reflect.ValueOf(u) mPrint:=v.MethodByName("Print") args:=[]reflect.Value{reflect.ValueOf("前缀")} fmt.Println(mPrint.Call(args))}type User struct{ Name string Age int}func (u User) Print(prfix string){ fmt.Printf("%s:Name is %s,Age is %d",prfix,u.Name,u.Age)}

      MethodByName方法可以让我们根据一个方法名获取一个方法对象,然后我们构建好该方法需要的参数,最后调用Call就达到了动态调用方法的目的。

      获取到的方法我们可以使用IsValid 来判断是否可用(存在)。

      这里的参数是一个Value类型的数组,所以需要的参数,我们必须要通过ValueOf函数进行转换。

    上一篇:Hi3536视频编解码之视频叠加
    下一篇:没有了
    网友评论