最近在写一个自动生成api文档的功能,用到了reflect包来给结构体赋值,给空数组新增一个元素,这样只要定义一个input结构体和一个output的结构体,并填写一些相关tag信息,就能使用程序来生成输入和输出的相关文档。golang
reflect包是golang中很重要的一个包,实现了在运行时容许程序操纵任意类型对象的功能。能够看下文档简单了解一下。json
在reflect中,最重要的是Value类,只有先获取到一个对象或者变量的Value对象后,咱们才能够对这个对象或者变量进行更进一步的分析和处理。咱们可使用reflect.ValueOf()方法获取Value对象。api
var i int value := reflect.ValueOf(i) // 使用ValueOf()获取到变量的Value对象 type S struct { a string } var s S value2 := reflect.ValueOf(s) // 使用ValueOf()获取到结构体的Value对象
获取到对象或者变量的Value对象后,咱们就能够对他们进一步的操做了。数组
Value.Type()和Value.Kind()这两个方法均可以获取对象或者变量的类型,若是是变量的话,使用这两个方法获取到的类型都是同样,差异是结构体对象,举个例子看一下:指针
var i int value := reflect.ValueOf(i) log.Println(value.Type()) //输出:int log.Println(value.Kind()) //输出:int type S struct { a string } var s S value2 := reflect.ValueOf(s) // 使用ValueOf()获取到结构体的Value对象 log.Println(value2.Type()) //输出:S log.Println(value2.Kind()) //输出:struct
变量i
使用kind和type两个方法都输出了int
,而结构体s
的Type()方法输出了S
,Kind()方法输出了struct
,由此能够总结以下,若是你想拿到结构体里面定义的变量信息的时候,使用Type(f)方法。若是只是相判断是不是结构体时,就使用Kind()code
获取变量的值使用value.Interface()方法,该方法会返回一个value的值,不过类型是interface。给变量赋值须要先判断该变量的类型,使用以前提到过的Value.Kind()方法,若是变量的类型是reflect.Int,咱们就可使用Value.SetInt()方法给变量赋值。下面是一个例子:对象
var i int = 1 // 获取Value,这里注意,若是你要改变这个变量的话,须要传递变量的地址 value := reflect.ValueOf(&i) // value是一个指针,这里获取了该指针指向的值,至关于value.Elem() value = reflect.Indirect(value) // Interface是获取该value的值,返回的是一个interface对象 log.Println(value.Interface()) // 输出:1 // 把变量i的值设为2 if value.Kind() == reflect.Int { value.SetInt(2) } log.Println(value.Interface()) // 输出:2
给结构体对象中的成员变量赋值的方法:文档
type S struct { A string // 注意:只有大写开头的成员变量能够Set } s := S{"x"} value := reflect.ValueOf(&s) value = reflect.Indirect(value) //value是结构体s,因此打印出来的是整个结构体的信息 log.Println(value.Interface()) //输出: {x} f0 := value.FieldByName("A") //获取结构体s中第一个元素a log.Println(f0) // 输出: x if f0.Kind() == reflect.String { if f0.CanSet() { f0.SetString("y") } } log.Println(f0) // 输出: y log.Println(value.Interface()) //输出: {y}
结构体这里须要注意的是,只有公有的成员变量能够被reflect改变值,私有的变量是没法改变值得。get
因为golang变量大小写和公有私有息息相关,因此码农门很难按照本身的意愿来定义变量名。因而golang提供了tag机制,来给变量提供一个标签,这个标签能够做为一个别名,来给一些存储结构来获取结构体变量名字使用。下面是一个获取结构体成员变量tag信息的例子:input
type S struct { A string `json:"tag_a"` } s := S{} value := reflect.ValueOf(&s) value = reflect.Indirect(value) //获取结构体s的类型S vt := value.Type() //获取S中的A成员变量 f, _ := vt.FieldByName("A") //获取成员变量A的db标签 log.Println(f.Tag.Get("json")) //输出: tag_a
未完待续。。。