go 反射

反射的概念

反射就是程序能夠在運行時動態(tài)的查看自己的狀態(tài)流译,比關(guān)切允許修改自
身的行為。
1肤无、GO的反射基礎(chǔ)是接口和類型系統(tǒng)先蒋,
2、反射的優(yōu)點:1)宛渐、通用性,可對類庫和框架代碼做極大的簡化設(shè)計眯搭;2)窥翩、靈活性,對一些測試工具的開發(fā)提供良好的支持鳞仙。
3寇蚊、反射的缺點:1)、脆弱棍好,不正確的修改很容易導(dǎo)致程序的崩潰仗岸;2)、難懂借笙,反射接口運行時扒怖,沒有具體的類型系統(tǒng)的約束,接口的抽象及實現(xiàn)細(xì)節(jié)復(fù)雜业稼,導(dǎo)致代碼難以理解盗痒;3)、性能損失低散,動態(tài)修改狀態(tài)必然不是直接的地址引用俯邓,而是借助運行時構(gòu)造一個抽象層來間接訪問,導(dǎo)致性能損失熔号。
4稽鞭、用途:盡量在一些庫或框架內(nèi)部代碼中使用。
5引镊、Golang語言實現(xiàn)了反射朦蕴,反射機(jī)制就是在運行時動態(tài)的調(diào)用對象的方法和屬性篮条,Golang的gRPC也是通過反射實現(xiàn)的。

所有類型通用的方法

//返回包含包名的類型名字梦重,對于未命名類型返回的是空
Name() string

//Kind返回該類型的底層基礎(chǔ)類型
Kind() Kind


//確定當(dāng)前類型是否實現(xiàn)了u接口類型
//注意這里的u必須是接口類型的Type
Implements(u Type) bool

//判斷當(dāng)前類型的實例是否能賦值給type為u的類型變量
AssignableTo(u Type) bool

//判斷當(dāng)前類型的實例是否能強(qiáng)制類型轉(zhuǎn)換為u類型變量
ConvertibleTo(u Type) bool

//判斷當(dāng)前類型是否支持比較(等于或不等于)
//支持等于的類型可以作為map的key
Comparable() bool

//返回一個類型的方法的個數(shù)
NumMethod() int

//通過索引值訪問方法兑燥,索引值必須屬于[0,NumMethod()]琴拧,否則引發(fā)panic
Method(int) Method

//通過方法名獲取Method
MethodByName(string) (Method,bool)

//返回類型的包路徑降瞳,如果類型是預(yù)聲明類型或未命名類型,則返回空字符串
PkgPath() string

//返回存放該類型的實例需要多大的字節(jié)空間
size() uintptr
package main

import (
    "fmt"
    "reflect"
)

type User struct {
    Id   int
    Name string
    Age  int
}

func (u User) ReflectCallFunc() {
    fmt.Println("Allen.Wu ReflectCallFunc")
}

func main() {

    user := User{1, "Allen.Wu", 25}

    DoFiledAndMethod(user)

}

// 通過接口來獲取任意參數(shù)蚓胸,然后一一揭曉
func DoFiledAndMethod(input interface{}) {

    getType := reflect.TypeOf(input)
    fmt.Println("get Type is :", getType.Name())

    getValue := reflect.ValueOf(input)
    fmt.Println("get all Fields is:", getValue)

    // 獲取方法字段
    // 1. 先獲取interface的reflect.Type挣饥,然后通過NumField進(jìn)行遍歷
    // 2. 再通過reflect.Type的Field獲取其Field
    // 3. 最后通過Field的Interface()得到對應(yīng)的value
    for i := 0; i < getType.NumField(); i++ {
        field := getType.Field(i)
        value := getValue.Field(i).Interface()
        fmt.Printf("%s: %v = %v\n", field.Name, field.Type, value)
    }

    // 獲取方法
    // 1. 先獲取interface的reflect.Type,然后通過.NumMethod進(jìn)行遍歷
    for i := 0; i < getType.NumMethod(); i++ {
        m := getType.Method(i)
        fmt.Printf("%s: %v\n", m.Name, m.Type)
    }
}


運行結(jié)果:
get Type is : User
get all Fields is: {1 Allen.Wu 25}
Id: int = 1
Name: string = Allen.Wu
Age: int = 25
ReflectCallFunc: func(main.User)
package main

import (
    "fmt"
    "reflect"
)

type User struct {
    Id   int
    Name string
    Age  int
}

func (u User) ReflectCallFuncHasArgs(name string, age int) {
    fmt.Println("ReflectCallFuncHasArgs name: ", name, ", age:", age, "and origal User.Name:", u.Name)
}

func (u User) ReflectCallFuncNoArgs() {
    fmt.Println("ReflectCallFuncNoArgs")
}

// 如何通過反射來進(jìn)行方法的調(diào)用沛膳?
// 本來可以用u.ReflectCallFuncXXX直接調(diào)用的扔枫,但是如果要通過反射,那么首先要將方法注冊锹安,也就是MethodByName短荐,然后通過反射調(diào)動mv.Call

func main() {
    user := User{1, "Allen.Wu", 25}
    
    // 1. 要通過反射來調(diào)用起對應(yīng)的方法,必須要先通過reflect.ValueOf(interface)來獲取到reflect.Value叹哭,得到“反射類型對象”后才能做下一步處理
    getValue := reflect.ValueOf(user)

    // 一定要指定參數(shù)為正確的方法名
    // 2. 先看看帶有參數(shù)的調(diào)用方法
    methodValue := getValue.MethodByName("ReflectCallFuncHasArgs")
    args := []reflect.Value{reflect.ValueOf("wudebao"), reflect.ValueOf(30)}
    methodValue.Call(args)

    // 一定要指定參數(shù)為正確的方法名
    // 3. 再看看無參數(shù)的調(diào)用方法
    methodValue = getValue.MethodByName("ReflectCallFuncNoArgs")
    args = make([]reflect.Value, 0)
    methodValue.Call(args)
}


運行結(jié)果:
ReflectCallFuncHasArgs name:  wudebao , age: 30 and origal User.Name: Allen.Wu
ReflectCallFuncNoArgs

說明
1忍宋、要通過反射來調(diào)用起對應(yīng)的方法,必須要先通過reflect.ValueOf(interface)來獲取到reflect.Value风罩,得到“反射類型對象”后才能做下一步處理

2糠排、reflect.Value.MethodByName這.MethodByName,需要指定準(zhǔn)確真實的方法名字超升,如果錯誤將直接panic入宦,MethodByName返回一個函數(shù)值對應(yīng)的reflect.Value方法的名字。

3室琢、[]reflect.Value乾闰,這個是最終需要調(diào)用的方法的參數(shù),可以沒有或者一個或者多個研乒,根據(jù)實際參數(shù)來定汹忠。

4、reflect.Value的 Call 這個方法雹熬,這個方法將最終調(diào)用真實的方法宽菜,參數(shù)務(wù)必保持一致,如果reflect.Value'Kind不是一個方法竿报,那么將直接panic铅乡。

5、本來可以用u.ReflectCallFuncXXX直接調(diào)用的烈菌,但是如果要通過反射阵幸,那么首先要將方法注冊花履,也就是MethodByName,然后通過反射調(diào)用methodValue.Call

使用反射的實例:inject包 依賴注入:https://www.zddhub.com/memo/2015/07/05/go-dependency-inject.html

反射三定律:
(1)反射可以從接口值得到反射對象挚赊;
(2)反射可以從反射對象獲取接口值诡壁;
(3)若要修改一個反射對象,則其值必須為可修改荠割。

1妹卿、Golang的gRPC也是通過反射實現(xiàn)的。
2蔑鹦、控制反轉(zhuǎn)夺克,依賴注入

類型斷言在GO中指的就是判斷接口型變量運行時的實際類型

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市嚎朽,隨后出現(xiàn)的幾起案子铺纽,更是在濱河造成了極大的恐慌,老刑警劉巖哟忍,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件狡门,死亡現(xiàn)場離奇詭異,居然都是意外死亡锅很,警方通過查閱死者的電腦和手機(jī)融撞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來粗蔚,“玉大人,你說我怎么就攤上這事饶火∨艨兀” “怎么了?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵肤寝,是天一觀的道長当辐。 經(jīng)常有香客問我,道長鲤看,這世上最難降的妖魔是什么缘揪? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮义桂,結(jié)果婚禮上找筝,老公的妹妹穿的比我還像新娘。我一直安慰自己慷吊,他們只是感情好袖裕,可當(dāng)我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著溉瓶,像睡著了一般急鳄。 火紅的嫁衣襯著肌膚如雪谤民。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天疾宏,我揣著相機(jī)與錄音张足,去河邊找鬼。 笑死坎藐,一個胖子當(dāng)著我的面吹牛为牍,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播顺饮,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼吵聪,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了兼雄?” 一聲冷哼從身側(cè)響起吟逝,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎赦肋,沒想到半個月后块攒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡佃乘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年囱井,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片趣避。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡庞呕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出程帕,到底是詐尸還是另有隱情住练,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布愁拭,位于F島的核電站讲逛,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏岭埠。R本人自食惡果不足惜盏混,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望惜论。 院中可真熱鬧许赃,春花似錦、人聲如沸来涨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蹦掐。三九已至技羔,卻和暖如春僵闯,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背藤滥。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工鳖粟, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人拙绊。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓向图,卻偏偏與公主長得像,于是被迫代替她去往敵國和親标沪。 傳聞我的和親對象是個殘疾皇子榄攀,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 第一次知道反射的時候還是許多年前在學(xué)校里玩 C# 的時候。那時總是弄不清楚這個復(fù)雜的玩意能有什么實際用途……然后發(fā)...
    勿以浮沙筑高臺閱讀 1,128評論 0 9
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對...
    cosWriter閱讀 11,105評論 1 32
  • 反射reflection 反射可大大提高程序的靈猴性金句,使得interface{}有更大的發(fā)揮余地 反射使用Type...
    kaxi4it閱讀 596評論 0 2
  • 在一個方法內(nèi)部定義的變量都存儲在棧中檩赢,當(dāng)這個函數(shù)運行結(jié)束后,其對應(yīng)的棧就會被回收违寞,此時贞瞒,在其方法體中定義的變量將不...
    Y了個J閱讀 4,418評論 1 14
  • 每個人都有年少輕狂的時候,我的早戀似乎來得有點早趁曼,長大后才明白军浆,那所謂的早戀只不 過是崇拜,根本談不上愛挡闰,頂多算是...
    談戀愛不可馬虎閱讀 432評論 0 0