zoukankan      html  css  js  c++  java
  • Go reflect包用法和理解

    reflect包中的具体方法

     

    reflect.TypeOfreflect.ValueOf可以将一个普通的变量转换成『反射』包中提供的TypeValue

    type Person struct {
        Name     string
        Sex      string
    }
    func (p *Person) Add(a, b string) {
        fmt.Printf("me %+v
    ", a+b)
    }
    func (p *Person) AddRes(a, b string) (string, error){
        if b == "boy" {
            return a + b, errors.New("its a boy")
        }
        return a+b, nil
    }
    func main() {
        funcName := "Add"
        typeT := &Person{}
        a := reflect.ValueOf("li")
        b := reflect.ValueOf("femal")
        in := []reflect.Value{a, b}
        reflect.ValueOf(typeT).MethodByName(funcName).Call(in)//如果是没有参数的函数就需要传nil
        //me lifemal
    
        c := reflect.ValueOf("J")
        d := reflect.ValueOf("boy")
        inr := []reflect.Value{c, d}
        funcName = "AddRes"
        ret := reflect.ValueOf(typeT).MethodByName("AddRes").Call(inr)
        fmt.Printf("ret is %+v
    ", ret)
        //ret is [Jboy <error Value>]
        for i := 0; i < len(ret); i++ {
            fmt.Printf("ret index:%+v, type:%+v, value:%+v
    ", i, ret[i].Kind(), ret[i].Interface())
        }
        //ret index:0, type:string, value:Jboy
        //ret index:1, type:interface, value:its a boy
    }

    通过reflect修改值,主要包括(指针指向的具体元素,slice的元素,结构体指针的字段,数组指针的元素)

    • 取地址:v := reflect.ValueOf(&x)

    • CanSet()来判断是否可以设置值

    • 判断v.Elem()是否可以设值

    • v.Elem()设置具体值

    ts := []int{1, 2, 3}
    tsV := reflect.ValueOf(ts)
    if tsV.Index(0).CanSet() {
         tsV.Index(0).Set(reflect.ValueOf(10))
    }
    fmt.Printf("ts is %+v
    ", ts)
    //10,2,3
    tsA := [3]int{1, 2, 3}
    tsAv := reflect.ValueOf(&tsA)
    if tsAv.Elem().Index(0).CanSet() {
         tsAv.Elem().Index(0).Set(reflect.ValueOf(10))
    }
    fmt.Printf("tsA is %+v
    ", tsA)
    
    //小tips,切片返回的就是地址
    func main() {
        ary := [3]int{1, 2, 3}//数组
        sli := []int{1, 2, 3}//切片
        a := ary
        b := sli
        fmt.Printf("ary is %p
    sli is %p
    a is %p
    b is %p
    ", &ary,sli,&a,b)
    }
    // ary is 0xc0000b6020
    // sli is 0xc0000b6040
    // a is 0xc0000b6060
    // b is 0xc0000b6040

    通过reflect判断某个实例是否实现了接口

    typeT := &Struct{}
    IF := reflect.TypeOf((*Interface)(nil)).Elem()
    tv := reflect.TypeOf(typeT)
    tv.Implements(IF)//true

    reflect对struct中的tag解析

    获取tag中的值

    type TagTest struct {
         Name string `json:"name_json"`
         Age  int    `json:"age_json"`
    }
    t := TagTest{Name: "tom", Age: 10}
    rtt := reflect.TypeOf(t)
    for i := 0; i < rtt.NumField(); i++ {
         field := rtt.Field(i)
         if json, ok := field.Tag.Lookup("json"); ok {
         fmt.Printf("tag is %+v, value is %+v
    ", json,field.Tag.Get("json"))
         }
    }

    field.Tag.Lookup()和field.Tag.Get()方法都是取tag的值,只不过Lookup会用第二个返回值返回是否存在这个tag,而Get方法若不存在这个tag会返回一个空字符串

    Name string json:"name,omitempty" omitempty表示如果字段为空,就忽略这个字段

    实例解析json数据获取tag

    package main
    
    import (
        "fmt"
        "reflect"
        "strings"
    )
    
    type Person struct {
        Name        string `label:"Person Name: " uppercase:"true"`
        Age         int    `label:"Age is: "`
        Sex         string `label:"Sex is: "`
        Description string
    }
    
    // 按照tag打印结构体
    func PrintUseTag(ptr interface{}) error {
    
        // 获取入参的类型
        t := reflect.TypeOf(ptr)
        // 入参类型校验
        if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct {
            return fmt.Errorf("参数应该为结构体指针")
        }
    
        // 取指针指向的结构体变量
        v := reflect.ValueOf(ptr).Elem()
        // 解析字段
        for i := 0; i < v.NumField(); i++ {
            // 取tag
            fieldInfo := v.Type().Field(i)
            tag := fieldInfo.Tag
    
            // 解析label tag
            label := tag.Get("label")
            if label == "" {
                label = fieldInfo.Name + ": "
            }
    
            // 解析uppercase tag
            value := fmt.Sprintf("%v", v.Field(i))
            if fieldInfo.Type.Kind() == reflect.String {
                uppercase := tag.Get("uppercase")
                if uppercase == "true" {
                    value = strings.ToUpper(value)
                } else {
                    value = strings.ToLower(value)
                }
            }
    
            fmt.Println(label + value)
        }
        return nil
    }
    func main() {
        person := Person{
            Name:        "Tom",
            Age:         29,
            Sex:         "Male",
            Description: "Cool",
        }
        PrintUseTag(&person)
    }

  • 相关阅读:
    截取表单提交的字符串信息转换成对象 -- 前端面试题(一)
    HTML5 简单归纳 -- 前端知识 (二)
    02_安装Linux
    01_Linux 简介
    Mysql学习笔记八:Mysql操作
    Mysql学习笔记七:常用SQL语句
    Mysql学习笔记六:事务
    Mysql学习笔记五:修改
    Mysql学习笔记四:查询
    Mysql学习笔记二:主键、外键
  • 原文地址:https://www.cnblogs.com/peterleee/p/13406125.html
Copyright © 2011-2022 走看看