美文网首页
golang-reflect 2021-11-21

golang-reflect 2021-11-21

作者: 9_SooHyun | 来源:发表于2021-11-21 17:58 被阅读0次

golang变量 = type + value

golang里,一个变量,只要确定了它的类型和值,就可以确定该变量

也因此,两个nil是无法比较的

package main

import "fmt"

func main() {
   fmt.Println(nil == nil) // invalid operation: nil == nil (operator == not defined on nil)
}

两个nil都是untyped的无类型值,无法比较

反射

在程序运行过程中获取变量的类型信息、字段名称、结构体信息和值等

反射信息由reflect.Type和reflect.Value两部分组成,分别由reflect.TypeOfreflect.ValueOf 两个函数来获取

涉及与变量有关的操作,使用reflect.Value相关的方法;别的操作,使用reflect.Type的相关方法

参考
http://c.biancheng.net/view/4407.html
https://draveness.me/golang/docs/part2-foundation/ch04-basic/golang-reflect/
https://eddycjy.com/posts/go/reflect/

反射的应用 struct to map[string]interface{} by reflect

一个结构体可以拥有多种类型的成员变量,可以映射成map[string]interface{}

package main

import (
    "reflect"
    "fmt"
)

type student struct {
    Name string `json:"stu_name"`
    Age int
    Sex string
}

func main() {
    s := student{
        Age: 10,
    }
    m := Struct2Map(s)
    fmt.Printf("%+v\n", m)
}

 
func Struct2Map(obj interface{}) map[string]interface{} {
    t := reflect.TypeOf(obj)  // 获取obj的反射类型
    v := reflect.ValueOf(obj)  // 获取obj的反射值
    var data = make(map[string]interface{})
    for i := 0; i < t.NumField(); i++ {
        // 存在tag,则使用tag作为key
        var key string
        tag := t.Field(i).Tag.Get("json")
        if tag != "" {
          key = tag
        } else {
          key = t.Field(i).Name
        }
        data[key] = v.Field(i).Interface()
    }
    return data
}


>>>
map[Age:10 Sex: stu_name:]

反射的应用 struct assign by reflect

package main

import (
    "fmt"
    "reflect"
)

type A struct {
    Name   string
    Gender string
    Age    int
}
type B struct {
    Name   string
    Gender string
}

// StructAssign sourceStruct将值赋予targetStruct同名同类型的字段
func StructAssign(targetStructPtr interface{}, sourceStructPtr interface{}) error {
    // 参数校验
    st := reflect.TypeOf(sourceStructPtr)
    if st.Kind() != reflect.Ptr {
        return fmt.Errorf("source must be a struct pointer")
    }
    tt := reflect.TypeOf(targetStructPtr)
    if tt.Kind() != reflect.Ptr {
        return fmt.Errorf("target must be a struct pointer")
    }
    //获取reflect.Type类型
    tVal := reflect.ValueOf(targetStructPtr).Elem()
    sVal := reflect.ValueOf(sourceStructPtr).Elem()
    // 遍历目标struct全部字段
    for i := 0; i < tVal.NumField(); i++ {
        // 在源结构体中查询有数据结构体中相同属性和类型的字段,有则修改其值
        // name := sTypeOfT.Field(i).Name
        f := tVal.Type().Field(i)
        name := f.Name
        targetFiled := sVal.FieldByName(name)
        if targetFiled.IsValid() && f.Type == targetFiled.Type() {
            tVal.Field(i).Set(reflect.ValueOf(sVal.FieldByName(name).Interface()))
        }
    }
    return nil
}

func main() {
    as := A{}
    bs := B{Name: "wfy", Gender: "男"}
    fmt.Println(as)
    err := StructAssign(&as, &bs)
    fmt.Println(err)
    fmt.Println(as)
}

// see https://go.dev/play/p/9BdE9Rj_Uwx

相关文章

网友评论

      本文标题:golang-reflect 2021-11-21

      本文链接:https://www.haomeiwen.com/subject/uxhmtrtx.html