溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Go語言之reflection

發(fā)布時間:2020-07-29 06:47:07 來源:網(wǎng)絡(luò) 閱讀:694 作者:故新 欄目:編程語言

reflection 反射

  • 反射可大大提高程序的靈活性,使得interface{}有更大的發(fā)揮余地
  • 反射使用TypeOf和ValueOf函數(shù)從接口中獲取目標對象信息
  • 反射會將匿名字段作為獨立字段(匿名字段本質(zhì))
  • 想要利用反射修改對象狀態(tài),前提是interface.data是settable,即pointer-interface
  • 通過反射可以"動態(tài)"調(diào)用方法

舉例

1、通過反射來獲取屬性信息,方法信息

//反射  練習(xí)
//獲取字段的類型信息,方法信息, 屬性信息
package main

import (
    "fmt"
    "reflect"
)

type User struct {
    Id int
    Name string
    Age int
}

func (user User) Hello(){
    fmt.Println("hello world")
}

func main() {
    user := User{Id:2, Name:"xiaoqiang",Age:30}
    info(user)
}

//定義一個方法
//此方法接收的是一個空接口
//這樣的話,其實是任何類型都可以接收了
func info(o interface{}) {
    //獲取o的類型
    t := reflect.TypeOf(o)

    fmt.Println("Type:\t", t.Name())

    //取出類型后,需要對類型進行校驗,
    //查看是否是規(guī)定的類型
    if k :=t.Kind(); k != reflect.Struct {
        //如果不是規(guī)定的Struct類型的話,就需要進行
        //異常處理
        fmt.Println("輸入?yún)?shù)的類型不匹配!")
        return
    }

    //獲取o的屬性
    v := reflect.ValueOf(o)
    fmt.Println("Fields:\n")

    //開始遍歷,輸出字段
    for i := 0; i < t.NumField(); i++ {
        //獲取屬性下標
        f := t.Field(i)
        val := v.Field(i).Interface()
        //輸出屬性的名稱,類型,對應(yīng)的值
        fmt.Printf("%6s:%v = %v\n", f.Name, f.Type, val)
    }

    //開始獲取 方法的基本信息
    for i:=0; i<t.NumMethod(); i++ {
        m := t.Method(i)
        fmt.Printf("%6s:%v\n", m.Name, m.Type)
    }

}

2、反射是如何 獲取 匿名字段呢?

//反射 是如何處理 匿名字段的?
package main

import (
    "reflect"
    "fmt"
)

type Stu struct {
    Id int
    Name string
    Age int
}

type Man struct {
    //這里你要注意一下,你創(chuàng)建的屬性,是有順序的,是有下標的
    //如Stu 下標 就是0, title下標就是1
    // Stu 就是匿名屬性
    Stu
    title string
}

func main() {
    //注意,對匿名字段進行初始化時的方式,其實本質(zhì)上跟其他屬性是一樣的
    m := Man{Stu:Stu{Id:2,Name:"Jack",Age:19}, title:"Manager"}
    t := reflect.TypeOf(m)

    //取匿名字段的方式
    //FieldByIndex 方法,傳入的是一個切片slice類型
    //第1個0,表示,匿名字段在Man中的下標位置
    //第2個0,表示,你要取匿名字段中哪個屬性的下標
    fmt.Printf("%#v\n", t.FieldByIndex([]int{0,0})) //取的是id
    fmt.Printf("%#v\n", t.FieldByIndex([]int{0,1})) //取的是Name
    fmt.Printf("%#v\n", t.FieldByIndex([]int{0,2})) //取的是Age

}

3、通過反射對基本類型進行修改


//如果通過反射,對基本類型進行修改
package main

import (
    "reflect"
    "fmt"
)

func main() {
    //下面測試,對基本類型的修改 操作
    x := 456
    //傳遞的參數(shù)是  地址
    v := reflect.ValueOf(&x)

    //Elem方法,是取出元素值來,然后通過setint方法,進行重新設(shè)置
    v.Elem().SetInt(789)

    fmt.Println(x)
}

4、通過反射 對復(fù)雜類型進行修改

//如果通過反射,對復(fù)雜類型進行修改
package main

import (
    "reflect"
    "fmt"
)

type Teac struct {
    Id int
    Name string
    Age int
}

func main() {
    teac := Teac{Id:5,Name:"Ant-man",Age:23}
    fmt.Println("teac:\t", teac)
    //傳遞的是 地址哦
    Set(&teac)
    fmt.Println("teac:\t", teac)
}

func Set(o interface{}) {
    v := reflect.ValueOf(o)
    if v.Kind() == reflect.Ptr && !v.Elem().CanSet() {
        fmt.Printf("xxx")
        return
    }else{
        v = v.Elem()
    }

    // 通過FieldByName 這個方法,直接輸入 名稱,來獲取
    f := v.FieldByName("Name")

    //校驗,是否取到Name屬性的值
    if !f.IsValid() {
        fmt.Printf("BAD")
        return
    }

    //然后,再校驗,類型是否匹配
    if f.Kind() == reflect.String {
        f.SetString("Iron Man")
    }

}

5、通過反射對方法進行動態(tài)調(diào)用

//通過反射,進行方法的調(diào)用,相當于動態(tài)調(diào)用了
package main

import (
    "fmt"
    "reflect"
)

type Teacher struct {
    Id int
    Name string
    Age int
}

//通過receiver將Show方法,跟Teacher類型,進行綁定
func (teacher Teacher)Show(name string) {
    fmt.Println("hello, ", name, ", my name is ", teacher.Name)
}

//注意======目前沒有發(fā)現(xiàn)====如何通過====反射===來獲取=====私有方法
func (teacher Teacher)info(){
    fmt.Println("=====")
}

func main() {
    teacher := Teacher{Id:34, Name:"Thor",Age:34}
    teacher.Show("Hawkeye")

    //下面通過反射,調(diào)用show方法
    v := reflect.ValueOf(teacher)
    //獲取show方法
    m := v.MethodByName("Show")

    //校驗一下,是否獲取到show方法呢
    if !m.IsValid() {
        fmt.Printf("=======沒有獲取到制定的方法====")
        return
    }

    //參數(shù)必須是切片類型
    //reflect.Value{}   這里面,可以設(shè)定多個參數(shù)類型
    //目前,我們這里只有一個string類型的參數(shù)
    //
    args := []reflect.Value{reflect.ValueOf("Hulk")}
    m.Call(args)
}
向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI