反射:能夠在運行時動態獲取變量的相關信息app
反射須要導入reflect函數
反射有幾下幾個重要的函數:
reflect.TypeOf :獲取變量的類型,返回reflect.Type類型
reflect.ValueOf:獲取變量的值,返回reflect.Value類型
reflect.Value.Kind:獲取變量的類別,返回一個常量
reflect.Value.Interface():轉換成interface{}類型spa
經過一個小例子來理解:指針
package main import ( "reflect" "fmt" ) type Student struct{ Name string Age int } func (s*Student) SetName(name string){ s.Name="coders" } func (s*Student)SetAge(age int){ s.Age = 23 } func getTypeInfo(a interface{}){ // 用於獲取一個數據的數據類型 typeInfo := reflect.TypeOf(a) kind := typeInfo.Kind() fmt.Println("kind of a :",kind) num := typeInfo.NumMethod() //獲取當前數據有多少個方法 fmt.Println("method num:",num) method,ok:=typeInfo.MethodByName("SetName") //獲取是否有某個方法 if !ok{ fmt.Println("not have method SetName") }else{ fmt.Println(method) } } func getAllMethod(a interface{}){ // 用於獲取變量下的全部方法 typeInfo := reflect.TypeOf(a) num := typeInfo.NumMethod() for i:=0;i<num;i++ { method:= typeInfo.Method(i) fmt.Println(method) } } func testGetAllMethod() { var stu Student getAllMethod(&stu) } func testGetTypeInfo(){ var i int getTypeInfo(i) //獲取的結果就是int var stu Student getTypeInfo(&stu) //獲取的結果就是struct getAllMethod(&stu) var s []int getTypeInfo(s) //獲取的結果就是slice var a [5]int getTypeInfo(a) //獲取的結果就是array } func testGetValueInfo(){ var i = 100 valueInfo := reflect.ValueOf(i) tmp := valueInfo.Interface() //轉換成interface類型 val := tmp.(int) //這裏我是知道是int因此直接轉換了 fmt.Println("val:",val) //這裏獲取的仍是100 fmt.Println("val of valueInfo:",valueInfo.Int()) // 這裏打印的也是100 fmt.Println("type:",valueInfo.Type()) fmt.Println("kind:",valueInfo.Kind()) } func main(){ testGetTypeInfo() testGetAllMethod() testGetValueInfo() }
上面這個例子中演示了reflect.Value.Kind()能夠返回int,struct,slice,array,固然這裏能夠返回的類型還有不少以下:
Bool
Int
Int8
Int16
Int32
Int64
Uint
Uint8
Uint16
Uint32
Uint64
Uintptr
Float32
Float64
Complex64
Complex128
Array
Chan
Func
Interface
Map
Ptr
Slice
String
Struct
UnsafePointercode
reflect.ValueOf(x).Float()
reflect.ValueOf(x).Int()
reflect.ValueOf(x).String()
reflect.ValueOf(x).Bool()blog
這個功能在上面的代碼中也有演示字符串
reflect.Value.SetXX相關方法,如:
reflect.Value.SetFloat():設置浮點數
reflect.Value.SetInt():設置整數
reflect.Value.SetString():設置字符串get
經過下面一個簡單的例子來演示:string
package main import ( "reflect" "fmt" ) func main() { var a float64 fmt.Println(a) fv := reflect.ValueOf(a) fv.SetFloat(3.14) fmt.Println(a) }
上面這段代碼會提示以下錯誤:class
這裏須要知道的是咱們的變量a是一個值類型的變量,咱們經過reflect.valueOf傳入的時候實際上是傳入的變量的拷貝,因此咱們若是經過SetFloat給變量設置值的時候其實並不會生效,go這裏已經替我考慮到了,因此給咱們提示了上面這個錯誤信息,那是否是咱們在reflect.Value的傳入地址就能夠了呢,我把上述代碼中更改成:reflect.Value(&a),當咱們運行後發現仍是報了和上面相同的錯誤,這是爲何呢?
咱們應該還記得若是是一個指針的時候咱們賦值的時候是須要在指針的左邊寫個*符號,可是這是在反射裏面咱們怎麼寫星號,因此go在這裏提供給咱們另一個方法,當咱們經過調用SetFloat的時候用:
fv.Elem().SetFloat(3.14)這種方式調用就ok了,完整的正確代碼爲:
package main import ( "reflect" "fmt" ) func main() { var a float64 fmt.Println(a) fv := reflect.ValueOf(&a) fv.Elem().SetFloat(3.14) fmt.Println(a) }
reflect.Value.NumField():獲取結構體中字段的個數
reflect.Value.Method(n).Call():調用結構體中的方法
package main import ( "reflect" "fmt" ) type Student struct{ Name string Age int Sex int } func (s *Student) Set(name string,age int,sex int){ s.Name = name s.Age = age s.Sex = sex } func testStruct() { var stu *Student = &Student{} stu.Set("coder",23,1) valueInfo := reflect.ValueOf(stu) fieldNum := valueInfo.Elem().NumField() fmt.Println("filed num:",fieldNum) //這裏返回的結果是3 sexValueInfo := valueInfo.Elem().FieldByName("Sex") fmt.Println("sex=",sexValueInfo.Int()) sexValueInfo.SetInt(0) //這裏是更改值 fmt.Println(stu) setMethod := valueInfo.MethodByName("Set") //獲取Set方法 var params []reflect.Value name := "tom" age := 18 sex:=2 params = append(params,reflect.ValueOf(name),reflect.ValueOf(age),reflect.ValueOf(sex)) setMethod.Call(params) //調用Set方法 fmt.Println(stu) //將最開始的值已經更改了 } func main() { testStruct() }