通过反射修改结构体字段值
代码
需要转入 指针 类型, 并调用 Elem() 方法 转化, 然后调用 SetXxx() 方法修改属性值
// 运用反射 修改 结构体 字段 案例// 反射可以用来开发底层框架package mainimport ("encoding/json""fmt""reflect")// 这就需要通过 tag 来转化大写的字段,同时又保证内部调用的时候可以暴露变量// 反射原理type People struct {Name string `json:"name01"`Age int `json:"age"`Height float64 `json:"height"`Action string}// 给结构体绑定方法func (p People) Print() {fmt.Println("print() = ", p)}func (p People) GetSum(n1, n2 int) int {return n1 + n2}func (p People) Set(name string, age int, height float64, action string) {p.Name = namep.Age = agep.Height = heightp.Action = action}func TestStruct(a interface{}) {typ := reflect.TypeOf(a)val := reflect.ValueOf(a)kd := val.Kind()if kd != reflect.Ptr && val.Elem().Kind() == reflect.Struct {fmt.Println("except struct, but its not")return}// 结构体字段// 字段的顺序跟定义结构体时字段的先后顺序一致num := val.Elem().NumField()fmt.Printf("struct has %v fields \n", num)for i := 0; i < num; i++ {fmt.Printf("第%v个字段:%v \n", i+1, val.Elem().Field(i))tagVal := typ.Elem().Field(i).Tag.Get("json")if tagVal != "" {fmt.Printf("第%v个字段, tag : %v \n", i+1, tagVal)}}// 结构体方法numOfMethod := val.NumMethod()fmt.Printf("struct 有 %v 个方法 \n", numOfMethod)// 内部方法名顺序,按照函数名的 ascii 码排序的val.Method(1).Call(nil)var params []reflect.Valueparams = append(params, reflect.ValueOf(10))params = append(params, reflect.ValueOf(40))res := val.Method(0).Call(params)fmt.Println("res = ", res[0].Int())// 修改结构体字段值val.Elem().Field(1).SetInt(20)}func main() {// structp1 := People{Name: "tom",Age: 18,Height: 178.5,Action: "衣食住行",}// 序列化就是通过反射机制获取到 tag 值p1Str, err := json.Marshal(p1)if err != nil {fmt.Println("序列化失败", err)} else {fmt.Println("p1Str = ", string(p1Str))}// 传入指针类型, 调用 Elem() 和 SetXxx()TestStruct(&p1)fmt.Println("p1 = ", p1)}/*print() = {tom 18 178.5 衣食住行}p1 = {tom 20 178.5 衣食住行}*/
使用反射机制,编写函数适配器,桥连接
代码
// reflect_test.go 单元测试// 使用反射机制,编写适配器函数 桥连接package testimport ("reflect""testing")// type User struct {// UserId string// Name string// }func TestReflectFunc(t *testing.T) {// 定义两个不同参数的函数call1 := func(v1 int, v2 int) {t.Log(v1, v2)}call2 := func(v1 int, v2 int, s string) {t.Log(v1, v2, s)}var (function reflect.ValueinValue []reflect.Valuen int)bridge := func(call interface{}, args ...interface{}) {n = len(args)inValue = make([]reflect.Value, n)for i := 0; i < n; i++ {inValue[i] = reflect.ValueOf(args[i])}function = reflect.ValueOf(call)// len(in) == 3, v.Call(in)代表调用v(in[0], in[1], in[2])function.Call(inValue)}bridge(call1, 1, 2)bridge(call2, 1, 2, "test2")}/*go test -v=== RUN TestReflectFuncreflect_test.go:17: 1 2reflect_test.go:20: 1 2 test2--- PASS: TestReflectFunc (0.00s)PASSok go_code/reflect/reflect04/main 0.545s*/
通过反射创建并操作结构体
代码
// reflect_test.go 测试用例// 通过反射创建并操作结构体package testimport ("reflect""testing")type User struct {UserId stringName string}func TestReflectStructPtr(t *testing.T) {var (model *Userst reflect.Typeelem reflect.Value)// 获取 *User 类型st = reflect.TypeOf(model)t.Log("reflect.TypeOf = ", st.Kind().String()) // ptr// st 真正指向的类型st = st.Elem()t.Log("reflect.TypeOf.Elem = ", st.Kind().String()) // struct// New 返回一个 Value 类型的值,该值持有一个指向类型为 typ 的新申请的零值的指针elem = reflect.New(st)t.Log("reflect.New", elem.Kind().String()) // ptrt.Log("reflect.New.Elem", elem.Elem().Kind().String()) // struct// model 就是创建的 User 结构体变量(实例)// 类型断言model = elem.Interface().(*User) // model 是 *User, 它的指向跟elem 是一样的elem = elem.Elem() // 取得 elem 指向的值// 结构体赋值elem.FieldByName("UserId").SetString("123456")elem.FieldByName("Name").SetString("xiao")t.Log("model model.Name", model, model.Name)}/*go test -v=== RUN TestReflectStructPtrreflect_test.go:24: reflect.TypeOf = ptrreflect_test.go:27: reflect.TypeOf.Elem = structreflect_test.go:30: reflect.New ptrreflect_test.go:31: reflect.New.Elem structreflect_test.go:39: model model.Name &{123456 xiao} xiao--- PASS: TestReflectStructPtr (0.00s)PASSok go_code/reflect/reflect05/test 0.740s*/
