最近在寫一個自動生成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
未完待續。。。