反射的最佳实践(2) | 学习笔记

简介: 快速学习反射的最佳实践(2)

开发者学堂课程【Go语言核心编程 - 面向对象、文件、单元测试、反射、TCP编程反射的最佳实践(2)】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址:https://developer.aliyun.com/learning/course/626/detail/9774


反射的最佳实践(2)

 

内容介绍

一、使用反射来获取 tag 标签

二、定义的适配器

三、使用反射操作任意的结构体类型

四、使用反射创建并操作结构体

 

一、使用反射来获取 tag 标签

使用反射的方式来获取结构体的 tag 标签,遍历字段的值,修改字段值,调用结构体方法。唯一的变化就是在 TestStruct 这里传了一个&a。然后再加 a 是原来的“黄狮子”就变成了“白象精”,又在原来的基础上加了一个Elem,就是希望在反射里面把它的字段改变过来。代码如下:

Package main

import(

encoding/json

“fmt”

“reflect”

)

type Monster struct{

Name string‘json:“Monster”'

Age int

Score float32

Sex string

}

func(s monster) Print() {

fmt. PrintIn(〝---start---〞)

fmt.PrintIn(s)

fmt.PrintIn(---end---)

func TestStruct(a interface {}) {

typ:=reflect.Typeof(a)

val:=reflect.Valueof(a)

Kd:=val.Kind()

If kd!=reflect.struct {

fmt PrintIn(〞expect struct〝)

return

}

num:val.Elem().NumField()

val.Elem().Field(0).SetString(“白象精”)

For i:=0;i

fmt Printf(〝%d%v\n,i,val.Elem().Field(i).Kind())

}

fmt Printf(“struct has %d fields\n”,num)

tag:tye.Elem().Field(0).Tag.Get(“json”)

fmt Printf(“tag=%s\n,tag)

numOfMethod:=val.Elem().NumMethod()

fmt Printf(“struct has %d methods\n”,numOfMethod)

val.Elem().Method(0).Call(nil)

}

Func main() }

var a Monster=Monster{

Name:“黄狮子”

Age:408,

Score:92.8,

//先说明一下,Marshal 就是通过反射获取到 struct 的 tag 值

result,_:json.Marshal(a)

fmt Println(“json result:”,string(result))

TestStruct(&a)

fmt Println(a)


二、定义的适配器

第二个应用也是一个非常经典的反射最佳实践,是适配器的写法。适配器的写法的代码在这里。这是一个测试用例,就要像测试用例那样去命名。注意文件命名时必须是 XXX test 这样的形式。前面的部分随便改,后面必须以 test 结尾。

1、定义了两个函数 test1和 test2

test1:=func(v1 int,v2 int){

t.Log(v1,v2)

}

test2=func(v1 lnt,v2 lnt,s string){

t.Log(v1,v2,s)

2、定义一个适配器函数用作统一处理接口,其大致接口如下:

bridge:=func(call interface{},args…interface{})

//内容

}

//实现调用 test1对应的函数

bridge(test1,1,2)

//实现调用 test2对应的函数

bridge(test2,1,2,“test2”)

3、要求使用反射机制来完成

4、代码如下:

Package test

import(

“testing”

“reflect”

)

//文件命名xxx_test.go

func TestReflectFunc(t*testing.T){

call1:=func(v1 lnt,v2 lnt){

t.Log(v1,v2)

}

call2:=func(v1 lnt,v2 lnt,s string){

t.Log(v1,v2,s)

}

var(

function reflect.Value

inValue [] reflect.Value

n  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)

Function.Call(inValue)

)

bridge(call1,1,2)

bridge(call2,1,2,“test2”)

 

三、使用反射操作任意的结构体类型

这里也写着测试用例,它可以去操作任何的结构体。先创建了一个 var,里面是一个 model,它是一个指针,是指向 user 的一个指针类型。然后 sv 是 reflect.Value 的一个类型。用 model 去获写 sv,这个地方是相当于一个指针类型的,然后写一个日志把它的类型打出来了。sv.Elem 就相当于取到了 reflect.Value。然后通过 FieldByName 找到了 UserId 并且设值。这个地方其实就是在提醒怎样去修改字段了。sv 原来是指针,取到它对应的真实的 reflect.Value,再调用 FieldByName 并把值设置进去。这就相当于可以操作任意的一种结构体。这个结构体是什么都可以帮助操作,在底层帮助操作。代码如下:

type user struct{

Userld string

Name string

}

Func TestReflectStruct(t*testing.T)

var(

model *user

sv reflect.Value

)

model=&user{}

sv=reflect.ValueOf(model)

t.LOG(“reflect.ValueOf”,sv.Kind().String())

t.LOG(“reflect.ValueOf.Elem”,sv.Kind().String())

sv.FieldByName(“Userld”).SetString(“12345678”)

sv.FieldByName(“Name”).SetString(“nickname”)

t.Log(“model”,model)

 

四、使用反射创建并操作结构体

就连结构体的创建都可以用反射来完成。

1、代码如下:

package test

import{

testing

reflect

)

type user struct{

Userld string

Name string

}

func TestReflectStructPtr(*Testing.T)

var

model *user

st reflect.Type

elem reflect.Value

)

st=fellect.Typeof(model)//获取类型*user

t.Log(〞reflect .Typeof,stKind().String())//.ptr

st=st.Elem()//st 指向的类型

t.Log(〞reflect .Typeof.Elem,stKind().String())//.struct

Elem=reflect.New(st)//New 返回一个 value 类型值,该值持有一个指向类型为 type 的新申请的零值的指针

t.Log(“reflect.New”,elem.Kind{}.String())//ptr

t.Log(“reflect.New.Elem”,elem.Elem().Kind().String{})//struct

//model 就是创建的 user 结构体变量(实例)

model=elem.interface().(*user)

//model 是 *user 它的指向和 elem 是一样的

elem=elem.Elem()//取得 elem 指向的值

elem.FieldByName(“Userld”).SetString(“12345678”)//赋值…

elem.FieldByName(“Name”).SetString(“nickname”)

T. Log=(“model model.Name”,model,model.Name)

首先有一个 var,里面有 user 的指针,有一个 type 类型,有一个 value 类型。然后注释写得非常详细,先获取 user,这个 st 就应该是一个指针。St.Kind 打印出来就是 ptr,st.Elem 让 st 指向真正的类型。reflect(New) 就类似于在 java 里面的那种在底层的创建对象。把这个指针传进去最后返回 elem。这个 elem 还不是一个实例,它是 new 了一个 value 类型的值,该值持有一个指向类型为 typ 的新申请的零值的指针。它里面还没有数据,但已经指向了一个 user 的地址。这个时候 model 和 elem 其实都指向了一个 user 的地址空间。这就意味着如果改变了其中之一值都会发生变化。通过 elem 取到了它真正指向的值。这个指针指向了一个真正的空间,这个空间就是 user 的一个空间。model 还是通过地址指向数据空间的。当把值设完以后,model 里面的值也会有了。首先 elem 是一个指针,它相当于先指向了一个地址,这个地址在指向了一个真正的数据空间。这个空间就是 user 的一个空间。紧接着做了一个 model 也指向了这个地址空间,elem.Elem 就当是 elem 换了一个地址。因为只有这样做才能往里面赋值。

相关文章
|
5月前
|
SQL 缓存 Java
ReflectionUtils反射工具:精要介绍与实战应用指南
ReflectionUtils反射工具:精要介绍与实战应用指南
|
安全 Java 测试技术
带你深入学习“反射”技术
带你深入学习“反射”技术
141 0
|
运维 Devops C#
【C#编程最佳实践 十七】反射工厂最佳实践
【C#编程最佳实践 十七】反射工厂最佳实践
90 0
|
SQL 监控 Java
魔法反射--java反射进阶(实战篇)
相信很多人在初学反射的时候也都会有这个想法(我就不相信就只有我一个人这么蠢!!) 大多数人不了解反射的原因并不是不了解, 而是不知道它到底能用来干什么 今天就来为大家分享一下反射的用法
85 0
|
安全 Java 程序员
魔法反射--java反射初入门(基础篇)
反射被应用于许多方面, spring的注解, jdbc的连接都是基于反射来实现的, 可能在工作中我们很少能用到反射, 但是在面试的过程中面试官经常会问道, 可以不用反射, 但作为一个程序猿, 还是应该了解了解的
96 0
|
网络协议 编译器 测试技术
反射的快速入门(2)|学习笔记
快速学习反射的快速入门(2)
反射的快速入门(2)|学习笔记
|
网络协议 测试技术 Go
反射的快速入门(1)|学习笔记
快速学习反射的快速入门(1)
反射的快速入门(1)|学习笔记
|
机器学习/深度学习 JSON 网络协议
反射的最佳实践(1) | 学习笔记
快速学习反射的最佳实践(1)
|
网络协议 测试技术 Go
反射的注意事项和细节(2) | 学习笔记
快速学习反射的注意事项和细节(2)