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]
    
  • 相关阅读:
    css3之背景background-origin,background-clip,background-size
    css3之字体@font-face
    css3之文本text-overflow 与 word-wrap, word-break
    Ng第十二课:支持向量机(Support Vector Machines)(三)
    Ng第十二课:支持向量机(Support Vector Machines)(二)
    Ng第十二课:支持向量机(Support Vector Machines)(一)
    Ng第十一课:机器学习系统的设计(Machine Learning System Design)
    Ng第十课:应用机器学习的建议(Advice for Applying Machine Learning)
    Ng第九课:神经网络的学习(Neural Networks: Learning)
    Ng第八课:神经网络表述(Neural Networks: Representation)
  • 原文地址:https://www.cnblogs.com/lanyangsh/p/11160444.html
Copyright © 2011-2022 走看看