1. 程式人生 > >Go基礎之--反射

Go基礎之--反射

image package int32 etag 分享圖片 3.1 完整 cal com

反射:可以在運行時動態獲取變量的相關信息

反射需要導入reflect

反射中重要函數的演示

反射有幾下幾個重要的函數:
reflect.TypeOf :獲取變量的類型,返回reflect.Type類型
reflect.ValueOf:獲取變量的值,返回reflect.Value類型
reflect.Value.Kind:獲取變量的類別,返回一個常量
reflect.Value.Interface():轉換成interface{}類型

通過一個小例子來理解:

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

獲取變量的值

reflect.ValueOf(x).Float()
reflect.ValueOf(x).Int()
reflect.ValueOf(x).String()
reflect.ValueOf(x).Bool()

這個功能在上面的代碼中也有演示

通過反射來改變變量的值

reflect.Value.SetXX相關方法,如:
reflect.Value.SetFloat():設置浮點數
reflect.Value.SetInt():設置整數
reflect.Value.SetString():設置字符串

通過下面一個簡單的例子來演示:

package main

import (
    "reflect"
    "fmt"
)

func main() {
    var a float64
    fmt.Println(a)
    fv := reflect.ValueOf(a)
    fv.SetFloat(3.14)
    fmt.Println(a)
}

上面這段代碼會提示如下錯誤:

技術分享圖片

這裏需要知道的是我們的變量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()
}

Go基礎之--反射