Go基礎之--反射

反射:能夠在運行時動態獲取變量的相關信息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 
UnsafePointer
code

獲取變量的值

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()
}
相關文章
相關標籤/搜索