1.判斷函數(shù)變量是否否和標準
2.驗證接口值是否合理如(是否為空,傳入的字段是否合規(guī))
3.獲取變量的類型進行斷言等操作
在Go語言的反射機制中,任何接口值都由是一個具體類型和具體類型的值兩部分組成的(我們在上一篇接口的博客中有介紹相關(guān)概念)。 在Go語言中反射的相關(guān)功能由內(nèi)置的reflect包提供,任意接口值在反射中都可以理解為由reflect.Type和reflect.Value兩部分組成,并且reflect包提供了reflect.TypeOf和reflect.ValueOf兩個函數(shù)來獲取任意對象的Value和Type。
reflect.TypeOf() 獲取類型信息,返回 Type 類型;
reflect.ValueOf() 獲取數(shù)據(jù)信息,返回 Value 類型。
反射中值的可設(shè)置性,可以用 CanSet 方法來判斷值是否可以設(shè)置。在 Go 中,函數(shù)參數(shù)的傳遞都是值拷貝,在反射中要修改值,必須傳遞指針,并且用 Elem() 方法獲取指針的值,然后進行修改。
在 type MyInt int 里,v.Kind() 與 v.Type() 返回了不同的類型值,Kind()返回的是 int,Type() 返回的是 MyInt。在 Go 中,可以用 type 關(guān)鍵字定義自定義類型,Kind() 方法返回底層類型。比如還有結(jié)構(gòu)體,指針等類型用 type 定義的,那么 Kind() 方法就可以獲取這些類型的底層類型。
package mainimport ( "fmt" "reflect")type Userinfo struct { Age int `id:"iloveyou" num:"222"` //tag標簽信息 UserName string}func GetReflickInfo(i interface{}) { vl := reflect.ValueOf(i) //nii := 200 fmt.Println("kind ======", vl.Kind()) if vl.Kind() == reflect.Ptr { //如是指針類型,先取值 vl = vl.Elem() //Elem方法就是取值操作 } vlt := vl.Type() //獲取具體類型,如自定義結(jié)構(gòu)體的類型 fmt.Println("kind ======type===", vl.Kind(), vlt) if vl.Kind() != reflect.Struct { fmt.Println("類型:", vlt, " 名字:", vlt.Name(), " 數(shù)值:", vl) //如是整數(shù)種類,又可以修改,CanSet屬性為true,則進行修改。 if vl.Kind() == reflect.Int || vl.Kind() == reflect.Int64 && vl.CanSet() { vl.SetInt(100) //reflect.New(vlt)是創(chuàng)建了一個vlt類型的指針變量。 ni := reflect.New(vlt) //創(chuàng)建后的ni是reflect.Value對象,需要通過ValueOf來賦值 ni = reflect.ValueOf(222) fmt.Println("修改后int數(shù)值:", vl, "新建數(shù)值:", ni) } //如是浮點數(shù)種類,又可以修改,CanSet屬性為true,則進行修改。 //可設(shè)置性檢查:vl.CanSet() 是一個方法,用于確認vl的值是否可以被修改。在Go中,不是所有的反射值都能被設(shè)置,比如函數(shù)參數(shù)或者某些靜態(tài)類型就不能。如果vl的值可以被改變,CanSet()將返回true。 if vl.Kind() == reflect.Float32 || vl.Kind() == reflect.Float64 && vl.CanSet() { vl.SetFloat(100.11) //調(diào)用vl.SetFloat(100.11)方法將變量vl的值設(shè)置為100.11。 fmt.Println("修改后float數(shù)值:", vl) } } else { fmt.Println("結(jié)構(gòu)體類型:", vlt, " 名字:", vlt.Name()) for i := 0; i < vl.NumField(); i++ { //vl是具體的值,這里vl.Field(i)就是枚舉出每一個成員的值 //vlt是獲取的類型,vlt.Field(i).Name和.Type是枚舉出每一個成員的名字和類型 //也可以使用FieldByName,從指定的成員名獲取具體值,vlret:= vl.FieldByName(vlt.Field(i).Name) fmt.Println("成員名:", vlt.Field(i).Name, " 類型:", vlt.Field(i).Type, " 數(shù)值:", vl.Field(i)) //如是字符串種類,又可以修改,CanSet屬性為true,則進行修改。 if vl.Field(i).Kind() == reflect.String && vl.Field(i).CanSet() { vl.Field(i).SetString("new str") fmt.Println("string成員修改后數(shù)值:", vl.Field(i)) } //而tag標簽信息都是靜態(tài)的,無須實例化結(jié)構(gòu)體,通過類型vlt可以獲取到。 //這句vlt.Field(i).Tag.Lookup("id")就是枚舉出每一個成員的tag標簽,看里面是否有id這個key,并返回它的value值 if idtag, b := vlt.Field(i).Tag.Lookup("id"); b { fmt.Println("tag id=", idtag) } if numtag, b := vlt.Field(i).Tag.Lookup("num"); b { fmt.Println("tag num=", numtag) } } }}func main() { var price float64 = 3.14 var age int64 = 5 bd := Userinfo{100, "andy"} ns := struct { //定義一個無名結(jié)構(gòu)體 id int addr string }{2, "aa"} GetReflickInfo(price) GetReflickInfo(&age) //把變量地址傳遞,所以可以修改。 GetReflickInfo(&bd) //把結(jié)構(gòu)體地址傳遞,所以可以修改。 fmt.Println(bd) //打印出修改后的結(jié)構(gòu)體變量 GetReflickInfo(ns)}
本文鏈接:http://www.tebozhan.com/showinfo-26-87989-0.html一篇學會Go中reflect反射的詳細用法
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。郵件:2376512515@qq.com