原文:medium.com/better-prog…golang
Go是一個強類型的靜態編程語言。然而,一些Go的特性讓它看起來又像是一門動態語言。例如,若是你不肯定你接收的參數的類型,你可使用interface
來接收全部類型的參數傳遞。編程
記住只有interface是有reflect屬性的。服務器
咱們注意到interface容許Go實現多態。沒有任何一種類型是特別須要強調的。能夠是string int64 float32 甚至是集合(array/map)。但計算機運行這些代碼時候,reflect幫助檢查,修改其自身的結構與行爲。這個過程容許咱們知道對象的類型以及內存在運行時的結構。編程語言
reflect兩個主要功能是reflect.Type
以及reflect.Value
。函數
簡單的說reflect.Type
提供參數的實際類型,當reflect.Value
結合_type
data
一塊兒使用的時候能夠容許開發者讀取或改寫參數的值。性能
func TypeOf(i interface{}) Type func ValueOf(i interface{}) Value 複製代碼
而後你可使用fmt.Printf()
和%T
來將參數進行格式化來或者reflect.TypeOf
的結果,以下:測試
fmt.Printf("%T", 3) //int
複製代碼
在reflect.Type
下toType
是一個改變數據類型的方法:網站
func toType(t * rtype) Type {
if t == nil {
return nil
}
return t
}
複製代碼
換句話說,reflect.Value
返回一個儲存在interface{}
中的變量。已經有不少方法包含如SetLen(n int)
,SetMapIndex(key, val Value)
,Int()
,TrySend(x refelect.Value)
等等。在完整版的文檔上,能夠參考src/reflect/value.go
spa
來自Go官方網站的使用場景:3d
經典的例子以下:
var x float64 = 3.4
v := reflect.ValueOf(x)
v.SetFloat(7.1) // Error: will panic
複製代碼
服務器在運行這段代碼時候會panic,由於v並非x,而是x的靠背。所以,全部對於v的修改都是禁止的。
因此,咱們須要使用指針來解決這個問題
var x float64 = 3.4
y := reflect.ValueOf(&x)
fmt.Println(「type of y」, y.Type()) // *float64
fmt.Println(「settability of y:」, y.CanSet()) // false
複製代碼
這時候y仍然不能代替x,你能夠經過y.Elem()
來修改
z := y.Elem()
z.SetFloat(7.1)
fmt.Println(z.Interface()) // 7.1
fmt.Println(x) // 7.1
複製代碼
能夠注意到指針會對所指向的值一併做出修改,也就是x
reflect
被普遍應用到對象序列化,fmt
相關函數,以及ORM等等上。
func Marshal(v interface{})([]byte, error) func Unmarshal(data []byte, v interface{}) error 複製代碼
兩個函數都接收interface類型做爲參數,所以在咱們運行函數內部時須要知道參數的值以及類型的時候,reflect
的get
set
方法就能起到做用了
在測試一個功能的時候,咱們每每須要知道兩個變量是否徹底一致。例如,判斷一個slice中全部的元素是否相同或者檢查兩個map中全部的key對應的value是否相同。這時就須要DeepEqual
函數
func DeepEqual(x, y interface{}) bool 複製代碼
DeepEqual
接收兩個interface的參數。你能夠傳入任意值,它會返回一個布爾值表示傳入的兩個參數是否徹底相等。
等一下,什麼叫作 deeply 相等,看看下面例子
type FirstInt int
type SecondInt int
func main() {
m := FirstInt(1)
n := SecondInt(1)
fmt.Println(reflect.DeepEqual(m, n)) // false
}
複製代碼
在上面例子中雖然m,n都是1,可是他們的數據類型是不同的,一個是FirstIn類型,一個是SecondInt類型。因此它們是不相等的。
Go做爲一門靜態語言,咱們能夠很是明確在語言編寫的彈性上來講相比於例如Python這樣的動態語言來講確定是有侷限性的。可是經過使用reflect
也讓咱們擁有了一部分動態語言的特性,你能夠很容易獲取參數的類型以及值,在使用它的時候。