深入理解Golang反射

反射

計算機中提到的反射一般是指振坚,程序借助某種手段檢查自己結(jié)構(gòu)的一種能力后众,通常就是借助編程語言中定義的類型(types)窑邦。因此垢油,反射是建立在類型系統(tǒng)上的。

go是靜態(tài)類型化琅催,每個變量都有一個靜態(tài)類型居凶,也就是說,在編譯時藤抡,變量的類型就已經(jīng)確定侠碧。不顯示地去做強制類型轉(zhuǎn)換,不同類型之間是無法相互賦值的缠黍。

有一種特殊的類型叫做接口(interface type)弄兜,一個接口表示的是一組方法集合。一個接口變量能存儲任何具體的值瓷式,只要這個值實現(xiàn)了這個接口的方法集合替饿。比如io包中的Reader和Writer,io.Reader接口變量能夠保存任意實現(xiàn)了Read方法的類型所定義的值贸典。

一個特殊接口就是空接口interface{}盛垦,任何值都可以說實現(xiàn)了空接口,因為空接口中沒有定義方法瓤漏,所以空接口可以保存任何值腾夯。

一個接口類型變量存儲了一對值:賦值給這個接口變量的具體值 + 這個值的類型描述符颊埃。更進一步的講,這個“值”是實現(xiàn)了這個接口的底層具體數(shù)據(jù)項(underlying concrete data item)蝶俱,而這個“類型”是描述了具體數(shù)據(jù)項(item)的全類型(full type)班利。

所以反射是干嘛的呢?反射是一種檢查存儲在接口變量中的(類型榨呆,值)對的機制罗标。reflect包中提供的2個類型Type和Value,提供了訪問接口值的reflect.Type和reflect.Value部分积蜻。

三大法則

  1. Reflection goes from interface value to reflecton object:從interface{} 變量可以反射出反射對象闯割;
type MyInt int32

func main() {
    var x MyInt = 7
    v := reflect.ValueOf(x)
    t := reflect.TypeOf(x)
    fmt.Println("type:", t)        // type: main.MyInt
    fmt.Println("value:", v)       // value: 7
    fmt.Println("kind:", v.Kind()) // kind: int32
    fmt.Println("type:", v.Type()) // type: main.MyInt
    x = MyInt(int32(v.Int))        // v.Int returns a int64
}

? reflect.Value的Type返回的是靜態(tài)類型MyInt,而kind()方法返回的是底層類型int32竿拆;為了保持API簡單宙拉,value的Setter和Getter類型方法操作,是包含某個值的最大類型丙笋,v.Int()返回的是int64谢澈,必要時轉(zhuǎn)化成實際類型。

  1. Reflection goes from reflection object to interface value:從反射對象可以獲取 interface{} 變量御板;
type MyInt int32

func main() {
    var x MyInt = 7
    v := reflect.ValueOf(x)
    y := v.Interface().(int32)
    fmt.Println(y) // 7
}

對于一個reflect.Value锥忿,可以用Interface方法恢復成一個接口值,效果就是包類型和值打包成接口怠肋,并返回結(jié)果敬鬓。

  1. To modify a reflection object, the value must be settable:要修改反射對象,其值必須可設置笙各;
func main() {
    var x float64 = 3.4
    v := reflect.ValueOf(x)
    // panic: reflect: reflect.flag.mustBeAssignable using addressable value
    v.SetFloat(7.1) 
    
    p := reflect.ValueOf(&X)
    // panic: reflect: reflect.flag.mustBeAssignable using addressable value
    p.SetFloat(7.1) 
    
    e := reflect.ValueOf(&X).Elem()
    // OK
    e.SetFloat(7.1) 
}

如果我們想通過反射來修改x列林,我們必須把我們想要修改的值的指針傳給一個反射庫。Go 語言的函數(shù)調(diào)用都是值傳遞的酪惭,所以我們只能先獲取指針對應的 reflect.Value希痴,再通過 reflect.Value.Elem 方法迂回的方式得到可以被設置的變量。我們通過如下所示的代碼理解這個過程:

func main() {
    i := 1
    v := &i
    *v = 10
}

如果不能直接操作 i 變量修改其持有的值春感,我們就只能獲取 i 變量所在地址并使用 *v 修改所在地址中存儲的整數(shù)砌创。

相關(guān)資料:

[1] Go語言中反射包的實現(xiàn)原理 https://studygolang.com/articles/2157

[2] 4.3反射 https://draveness.me/golang/docs/part2-foundation/ch04-basic/golang-reflect/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市鲫懒,隨后出現(xiàn)的幾起案子嫩实,更是在濱河造成了極大的恐慌,老刑警劉巖窥岩,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件甲献,死亡現(xiàn)場離奇詭異,居然都是意外死亡颂翼,警方通過查閱死者的電腦和手機晃洒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進店門慨灭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人球及,你說我怎么就攤上這事氧骤。” “怎么了吃引?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵筹陵,是天一觀的道長。 經(jīng)常有香客問我镊尺,道長朦佩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任庐氮,我火速辦了婚禮语稠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘旭愧。我一直安慰自己,他們只是感情好宙暇,可當我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布输枯。 她就那樣靜靜地躺著,像睡著了一般占贫。 火紅的嫁衣襯著肌膚如雪桃熄。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天型奥,我揣著相機與錄音瞳收,去河邊找鬼。 笑死厢汹,一個胖子當著我的面吹牛螟深,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播烫葬,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼界弧,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了搭综?” 一聲冷哼從身側(cè)響起垢箕,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎兑巾,沒想到半個月后条获,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡蒋歌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年帅掘,在試婚紗的時候發(fā)現(xiàn)自己被綠了委煤。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡锄开,死狀恐怖素标,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情萍悴,我是刑警寧澤头遭,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站癣诱,受9級特大地震影響计维,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜撕予,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一鲫惶、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧实抡,春花似錦欠母、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至啄清,卻和暖如春六水,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背辣卒。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工掷贾, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人荣茫。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓想帅,卻偏偏與公主長得像,于是被迫代替她去往敵國和親啡莉。 傳聞我的和親對象是個殘疾皇子博脑,可洞房花燭夜當晚...
    茶點故事閱讀 42,828評論 2 345

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

  • [TOC] Golang的反射reflect深入理解和示例 【記錄于2018年2月】 編程語言中反射的概念 在計算...
    AllenWu閱讀 862評論 1 14
  • 編程語言中反射的概念 在計算機科學領(lǐng)域,反射是指一類應用票罐,它們能夠自描述和自控制叉趣。也就是說,這類應用通過采用某種機...
    豆瓣奶茶閱讀 12,616評論 0 31
  • 歡迎訪問博客原文:http://pengtuo.tech/golang/2019/09/23/golang-ref...
    PeTu閱讀 623評論 0 0
  • 序言 第一次接觸反射技術(shù)是在很多年前學習設計模式的時候该押,那時在優(yōu)化Java版簡單工廠的實現(xiàn)疗杉,當讀取配置信息中的的類...
    _張曉龍_閱讀 4,629評論 2 21
  • 公司:叢迪服裝有限公司 【日精進打卡第784天】 【知~學習】 《六項精進》大綱0遍,共406遍; 《六項精進》通...
    阿詩瑪_6209閱讀 140評論 0 0