golang中的reflect包用法

最近在寫一個自動生成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對象後,咱們就能夠對他們進一步的操做了。數組

1.獲取對象或者變量的類型(Value.Type()和Value.Kind())

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

2.獲取變量的值和給變量賦值

獲取變量的值使用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

3.獲取結構體成員變量的tag信息

因爲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

未完待續。。。

相關文章
相關標籤/搜索