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]
原文地址:https://www.cnblogs.com/lanyangsh/p/11160444.html