11
golang 用反射reflect操作结构体
source link: https://blog.csdn.net/oqqYuan1234567890/article/details/90741112
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
- 需要遍历结构体的所有field
- 对于exported的field, 动态set这个field的value
- 对于unexported的field, 通过强行取址的方法来获取该值(tricky?)
下面的代码实现了从一个strct ptr对一个包外结构体进行取值的操作,这种场合在笔者需要用到反射的场合中出现比较多
simpleStrtuctField 函数接受一个结构体指针,因为最后希望改变其值,所以传参必须是指针。然后解引用。
接下来遍历结构体的每个field, exported字段是CanInterface的,对于unexported字段,需要强行取址来获取其值
model.go
package model
type Person struct {
Name string
age int
}
func NewPerson(name string, age int) *Person {
return &Person{
Name: name,
age: age,
}
}
main.go
package main
import (
"github.com/miaomiao3/log"
"../model"
"reflect"
"unsafe"
)
func main() {
person := model.NewPerson("haha", 12)
log.Debug("before:%+v", person)
simpleStrtuctField(person)
simpleStrtuctField(person)
log.Debug("after:%+v", person)
}
// get unexported field
func simpleStrtuctField(v interface{}) {
dataType := reflect.TypeOf(v)
dataValue := reflect.ValueOf(v)
if dataType.Kind() == reflect.Ptr {
if dataValue.IsNil() {
panic("nil ptr")
}
// 如果是指针,则要判断一下是否为struct
originType := reflect.ValueOf(v).Elem().Type()
if originType.Kind() != reflect.Struct {
return
}
// 解引用
dataValue = dataValue.Elem()
dataType = dataType.Elem()
} else {
panic("non ptr")
}
num := dataType.NumField()
for i := 0; i < num; i++ {
field := dataType.Field(i)
fieldName := field.Name
fieldValue := dataValue.FieldByName(fieldName)
if !fieldValue.IsValid() {
continue
}
if fieldValue.CanInterface() {
log.Debug("exported fieldName:%v value:%v", fieldName, fieldValue.Interface())
if fieldValue.CanSet() && fieldValue.Kind() == reflect.String {
oldValue := fieldValue.Interface().(string)
fieldValue.SetString(oldValue + " auto append")
}
} else {
// 强行取址
forceValue := reflect.NewAt(fieldValue.Type(), unsafe.Pointer(fieldValue.UnsafeAddr())).Elem()
log.Debug("unexported fieldName:%v value:%v", fieldName, forceValue.Interface())
}
}
}
output:
2019/06/02 17:15:31.64 [D] before:&{Name:haha age:12}
2019/06/02 17:15:31.64 [D] exported fieldName:Name value:haha
2019/06/02 17:15:31.64 [D] unexported fieldName:age value:12
2019/06/02 17:15:31.64 [D] after:&{Name:haha auto append age:12}
可以看到,Name字段被反射改变了,age的值也已经获取到
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK