Golang的反射
反射是指,在程式執行的時候,可以動態的檢查自身的型別,結構和其他資訊。
要了解Go語言的反射,我們需要了解兩個概念。
reflect.Type reflect.Value
我們想要在執行時知道型別和值,怎麼辦呢?很明顯就是編譯器幫我們把這些資訊存下來在程式的某個地方。 Type就是型別,Value就是值。reflect包裡有幾個重要的函式,需要了解一下:
-
reflect.TypeOf
獲取所傳入值的型別,返回的是reflect.Type
。而Type又分為很多種Kind,Kind有這麼幾種取值:
const ( Invalid Kind = iota Bool Int Int8 Int16 Int32 Int64 Uint Uint8 Uint16 Uint32 Uint64 Uintptr Float32 Float64 Complex64 Complex128 Array Chan Func Interface Map Ptr Slice String Struct UnsafePointer )
有點暈是不是?多看幾遍就不暈了。
-
reflect.ValueOf
返回所傳入值的值,但是型別是reflect.Value
。根據reflect.Value
可以拿到它的 Type,使用Type()
:
package main import ( "fmt" "reflect" ) func main() { v := reflect.ValueOf(3) fmt.Printf("TypeOf: %s\n", v.Type()) }
-
Value.CanSet
返回這個Value是不是能被更新值。設想,如果我們想從環境變數裡,把環境變數裡設定的值刷到一個結構體裡,就需要 用到這個函數了。注意,只有變數才能被更新,什麼是變數呢?就是,我們可以拿到它在記憶體中的地址,我們就可以更改值的意思。看看下面的例子:
x := 2 // 2 是常量,x是變數,x存的值是2。x是可以被更新的。 a := reflect.ValueOf(2) // a 不是變數,因為a代表的值是2,是一個常量。 b := reflect.ValueOf(x) // b 不是變數,因為b代表的值是x包含的值,也是2,是一個常量。 c := reflect.ValueOf(&x) // c 不是變數,因為c代表的值是x的地址,例如0x11223344,也是一個常量。 d := c.Elem() // d是變數,因為c是x的地址的值,c.Elem() 是x地址所指向的那個值,我們知道了x的地址,自然就可以更新x了。
有點難理解對不對?難就對了,因為這個要對記憶體有一定的瞭解,如果實在看不懂,就還是去看看基礎的書吧。我目前一句兩句話也解釋不清楚。 如果想理解的話,推薦:
- 《深入理解計算機系統》
- 《程式設計正規化》
- ofollow,noindex" target="_blank">https://blog.golang.org/laws-of-reflection
- 《The Go Programming Language》
- https://golang.org/pkg/reflect