zoukankan      html  css  js  c++  java
  • golang 通过reflect反射修改值

    不是所有的反射值都可以修改。对于一个反射值是否可以修改,可以通过CanSet()进行检查。

    要修改值,必须满足:

    • 可以寻址

      可寻址的类型:

      • 指针指向的具体元素
      • slice的元素
      • 可寻址的结构体的字段(指向结构体的指针)
      • 可寻址的数组的元素(指向数组的指针)
    • 不是结构体没有导出的字段

    1.指针指向的具体元素

    需要两步:

    • 取地址:v := reflect.ValueOf(&x)
    • 取得具体值 v=v.Elem()

    下面通过一个整型变量的赋值进行说明。

    package main
    
    import (
            "fmt"
            "reflect"
    )
    
    
    func main() {
    
            a := 1
    
            v := reflect.ValueOf(a)
    
            fmt.Println("v Type:", v.Type())
            fmt.Println("v CanSet:", v.CanSet())
    
            v = reflect.ValueOf(&a)
            fmt.Println("v Type:", v.Type())
            fmt.Println("v CanSet:", v.CanSet())
    
            v = v.Elem() // element value
            fmt.Println("v Type:", v.Type())
            fmt.Println("v CanSet:", v.CanSet())
            
            // set
            v.SetInt(2)
            fmt.Println("after set, v:", v)
    
            newValue := reflect.ValueOf(3)
            v.Set(newValue)
            fmt.Println("after set, v:", v)
    
    }
    

    定义一个整型变量,得到反射值,检查是否可以修改。

    接着,通过反射获取整型变量地址的反射值,再通过Elem()得到指针指向的具体对象,这样就可以修改值。

    输出结果:

    v: 1
    v Type: int
    v CanSet: false
    v Type: *int
    v CanSet: false
    v Type: int
    v CanSet: true
    after set, v: 2
    after set, v: 3
    

    2.slice的元素

    需要两步:

    • 取切片:v := reflect.ValueOf(s)
    • 获取切片的元素 e := v.Index(0)

    具体代码如下。

    package main
    
    import (
            "fmt"
            "reflect"
    )
    
    
    func main() {
    
            a := []int{1,1}
    
            v := reflect.ValueOf(a)
            fmt.Println("v:", v)
    
            fmt.Println("v Type:", v.Type())
            fmt.Println("v CanSet:", v.CanSet())
    
            e := v.Index(0)
            fmt.Println("e CanSet:", e.CanSet())
    
            e.SetInt(2)
    
            fmt.Println("after set:", v)
    }
    

    定义一个slice,得到反射值,从slice 的反射值中元素,
    接着,修改元素的值。

    结果输出:

    v: [1 1]
    v Type: []int
    v CanSet: false
    e CanSet: true
    after set: [2 1]
    

    3.可寻址的结构体的字段

    需要三步:

    • 取结构体地址 v := reflect.ValueOf(&a)
    • 获取结构体的具体值:Elem()
    • 获取结构体的字段:FieldByName()
    package main
    
    import (
            "fmt"
            "reflect"
    )
    
    type Orange struct {
            Size int
    }
    
    func main() {
    
            a := Orange{99}
    
            v := reflect.ValueOf(a)
            fmt.Println("v:", v)
    
            fmt.Println("v Type:", v.Type())
            fmt.Println("v CanSet:", v.CanSet())
    
            v = reflect.ValueOf(&a)
            fmt.Println("v:", v)
    
            fmt.Println("v Type:", v.Type())
            fmt.Println("v CanSet:", v.CanSet())
    
            //element
            v = v.Elem()
    
            size := v.FieldByName("Size")
            fmt.Println("size CanSet:", size.CanSet())
    
            size.SetInt(88)
    
            fmt.Println("after set:", v)
    
    }
    

    定义一个结构体变量,首先反射变量,检查是否可以修改值。
    接着,使用变量地址进行反射,通过Elem()获取指针指向的具体值。
    最后,获取结构体的字段,并修改值。

    输出结果

    v: {99}
    v Type: main.Orange
    v CanSet: false
    v: &{99}
    v Type: *main.Orange
    v CanSet: false
    size CanSet: true
    after set: {88}
    

    4.可寻址的数组的元素

    需要三步:

    • 取数组地址 v := reflect.ValueOf(&a)
    • 获取反射对象中的具体值:Elem()
    • 通过索引获取元素:Index(0)
    package main
    
    import (
            "fmt"
            "reflect"
    )
    
    func main() {
    
            a := [2]int{1,1}
    
            v := reflect.ValueOf(a)
            fmt.Println("v:", v)
    
            fmt.Println("v Type:", v.Type())
            fmt.Println("v CanSet:", v.CanSet())
    
            e := v.Index(0)
            fmt.Println("e Type:", e.Type())
            fmt.Println("e CanSet:", e.CanSet())
    
            v = reflect.ValueOf(&a)
            fmt.Println("v:", v)
    
            fmt.Println("v Type:", v.Type())
            fmt.Println("v CanSet:", v.CanSet())
    
            // element
            v = v.Elem()
            e = v.Index(0)
            fmt.Println("e Type:", e.Type())
            fmt.Println("e CanSet:", e.CanSet())
    
            e.SetInt(3)
    
            fmt.Println("after set:", v)
    
    }
    

    定义一个数组变量,首先反射变量,检查是否可以修改值。
    接着,取数组中的元素,检查是否可以修改值。

    使用数组的地址进行反射,通过Elem()获取指针指向的具体值。
    最后,获取数组中的元素,并修改值。

    输出结果

    v: [1 1]
    v Type: [2]int
    v CanSet: false
    e Type: int
    e CanSet: false
    v: &[1 1]
    v Type: *[2]int
    v CanSet: false
    e Type: int
    e CanSet: true
    after set: [3 1]
    
  • 相关阅读:
    conda创建、删除、重命名环境
    jupyter notebook选择conda环境
    conda 创建tensorflow虚拟环境后,无法import tensorflow在jupyter
    labelme2coco
    MacOs 10.14.3 Matlab2018b 解决“找不到已安装的编译器 'Xcode Clang++'。错误使用mex,未找到合适的编译器”问题
    MaskRCNN 奔跑自己的数据
    labelme2coco问题:TypeError: Object of type 'int64' is not JSON serializable
    kill 掉 占据端口的进程
    关于对多层嵌套的json字符串取目标值的问题
    关于Jmeter测试移动端应用时提示非法登录,不是合法的登录设备时的解决办法
  • 原文地址:https://www.cnblogs.com/lanyangsh/p/11160444.html
Copyright © 2011-2022 走看看