Go語言之反射

筆者本來是C++開發人員,以前對於反射沒太大概念,學了GO以後,纔開始接觸,在研究了一段時間以後,有了些認識,便整理一個帖子,但願對你們有所幫助。golang

在學習反射的時候,筆者一直在問本身,反射是什麼?爲何要用到反射?它是怎麼實現的?筆者以爲,在知道這些問題的答案以後,纔算是真正瞭解反射。下面筆者便從這些問題來着手整理反射。web

1、反射是什麼?

維基百科上的定義:編程

在計算機科學中,反射是指計算機程序在運行時(Run time)能夠訪問、檢測和修改它自己狀態或行爲的一種能力。用比喻來講,反射就是程序在運行的時候可以「觀察」而且「修改」本身的行爲。json

《Go 語言聖經》中是這樣定義反射的:數組

Go 語言提供了一種機制在運行時更新變量和檢查它們的值、調用它們的方法,可是在編譯時並不知道這些變量的具體類型,這稱爲反射機制。微信

經過上面的描述,咱們能看出來,反射是「元編程」的一種實現手段,它表如今運行階段,是對運行代碼的一種再編譯。數據結構

2、反射能幹什麼?

這裏只是針對GO語言的反射來描述,反射主要用在下面兩種狀況下:函數

場景一:性能

參數的入參是空的interface,也就是說參數的入參須要在該函數被執行的時候,才能知道這個入參究竟是什麼類型。學習

這種狀況產生的緣由: 每每是函數定義的時候,但願該入參能夠支持不少的數據類型,或者說定義該函數的時候,並無想好這個入參應該是什麼數據類型。

例如: json的序列化操做。

場景二:

程序在執行到一處代碼的時候,它到底要調用哪個函數,取決於當前傳遞的數據是什麼規則,而不一樣的規則須要調用不一樣的函數,這種狀況下也須要用到反射。

例如:webserver在接收到不一樣的uri的時候,須要使用不一樣的函數來處理,這就是很典型的一個例子。

全部的事情都有正反兩面,反射也不例外,引入反射以後,會有下面的一些很差的地方

1.代碼可讀性變低,對開發人員不是那麼友好,閱讀代碼的難度上升一個層級。

2.反射使用後,會避過了編譯階段的類型檢查,致使本來有可能在編譯階段發現的問題被隱藏掉。

3.反射對性能影響仍是比較大的,比正常代碼運行速度慢一到兩個數量級,若是系統對性能要求很高,就須要慎用反射。

3、反射是怎麼使用的?

在此以前,咱們須要先看下,反射的三個定律,以下所示:

1.Reflection goes from interface value to reflection object.(反射可以將 interface 中的類型和值轉換成真實的反射對象。)

2.Reflection goes from reflection object to interface value.(反射可以將真實的反射對象轉變成真實類型。)

3.To modify a reflection object, the value must be settable.(若是像修改反射生成的反射對象,這個數值必須是可修改的。)

定律一:將空接口轉換成反射對象

咱們經過reflect.Typeof()來顯示,真實的對象類型,例子以下:

func TypeOf(i interface{}) Type  //  Typeof()的定義能夠看出參數是一個空的interface


咱們經過reflect.ValueOf()來顯示真實對象存儲的數值,例子以下所示:

type Value struct {// contains filtered or unexported fields}

func ValueOf(i interface{})Value // ValueOf的入參也是一個空接口


經過MethodByName來獲取對應名稱的函數,並調用


備註:GetName()本來只是一個返回值,可是輸出結果倒是[Hello]數組的緣由是,Value.Call()函數的返回值是一個[]reflect.Value的數組。

定律二:將反射對象轉換成原類型

reflect.ValueOf轉換成的反射類型,能夠經過Interface方法把它恢復成一個接口值,固然咱們能夠直接將這個接口值轉換成對應的原數據,例子以下所示:



定律三:修改反射對象的值

reflect.ValueOf函數返回的是一份值的拷貝,因此直接對這個值進行修改是無心義的,由於它不會更改原來的那個值。

要想修改原來的數值,須要借用指針的特性,進行修改,這裏也就是定律三中提到的可設置性,經過Elem()來找到對應的原數據值。

例子以下所示:


4、反射的原理是什麼?

反射的實現是以空接口做爲基礎的,能夠說空的接口是反射實現的基石。空接口相似於C語言中的void*,它能夠轉換成任何類型的數值。

當咱們使用反射特性時,實際上用到的就是存儲在 interface 變量中的和類型相關的信息,也就是常說的 <type, value>。

主要涉及到的數據結構和函數以下所示:



5、參考文檔:

Go語言三大反射定律:https://blog.golang.org/laws-of-reflection

Go接口詳解:https://zhuanlan.zhihu.com/p/27055513

深度解密Go語言之反射:https://zhuanlan.zhihu.com/p/64884660


灰子學技術:



本文分享自微信公衆號 - 灰子學技術(huizixueguoxue)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索