反射是Go語言學習中一個比較難的點,須要好好探索一下。json
咱們知道,不管是int,float,bool等基礎數據類型,亦或是array,slice,map,chan等引用類型,當使用這些類型來定義的變量,在程序編譯時,編譯器已經知道變量的具體類型和具體值。bash
但不少時候,當咱們使用接口類型(interface{})定義變量時,接口類型的具體類型與具體值,須要在程序運行時才能肯定,且能夠動態變化,所以須要一種技術來檢測變量在程序運行中的具體類型和值。框架
Go反射技術就是這樣一種用來檢查未知類型和值的機制與方法。函數
當咱們須要實現一個通用的函數時,好比實現一個相似fmt.Sprint這樣的打印函數時,能夠根據不一樣的數據類型,返回出不一樣格式的數據,咱們也實現一個相似fmt.Sprint()函數但只能夠打印一個參數的Sprint函數,代碼以下:學習
type stringer interface {
String() string
}
func Sprint(x interface{}) string {
switch x := x.(type) {
case stringer:
return x.String()
case string:
return x
case int:
return strconv.Itoa(x)
// 還有int16, uint32,或者更多咱們自定義的未知類型.
case bool:
if x {
return "true"
}
return "false"
default:
// 默認返回值
return "???"
}
}
複製代碼
在上面打印函數中,咱們只是判斷了幾種基礎類型,但這是不夠,還有許多類型沒有判斷,雖然咱們能夠在上面的switch結構中繼續增長分支判斷,但在實際的程序中,還更多自定義的未知類型,所以須要使用反射技術來實現。ui
Go語言反射技術是由reflect包來實現,這個包主要定義了reflect.Type和reflect.Value兩個重要的類型。spa
reflect.Type是一個接口,表明一個的具體類型,使用reflect.TypeOf()函數,能夠返回reflect.Type的實現,reflect.TypeOf()方法能夠接收任何類型的參數,以下:code
t := reflect.TypeOf(100)
fmt.Println(t)//int
複製代碼
reflect.Value是一個reflect包中定義的結構體,表明一個類型的具體值,使用reflect.ValueOf()函數能夠返回一個reflect.Value值,reflect.ValueOf()能夠接收任意類型的參數。orm
使用reflect.Value中的Type()方法,能夠返回對應的reflect.Type。xml
v := reflect.ValueOf(10)
fmt.Println(v)
t := v.Type()
fmt.Println(t)
複製代碼
所以,咱們可使用反射來修改上面的Spring函數。
func Sprint(vv interface{}) string {
v := reflect.ValueOf(vv)
switch v.Kind() {
case reflect.Invalid:
return "invalid"
case reflect.Int, reflect.Int8, reflect.Int16,
reflect.Int32, reflect.Int64:
return strconv.FormatInt(v.Int(), 10)
case reflect.Uint, reflect.Uint8, reflect.Uint16,
reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return strconv.FormatUint(v.Uint(), 10)
case reflect.Bool:
return strconv.FormatBool(v.Bool())
case reflect.String:
return strconv.Quote(v.String())
case reflect.Chan, reflect.Func, reflect.Ptr, reflect.Slice, reflect.Map:
return v.Type().String() + " 0x" +
strconv.FormatUint(uint64(v.Pointer()), 16)
default:
return v.Type().String() + " value"
}
}
複製代碼
Golang提供的反射reflect包,是用於檢測類型、修改類型值、調用類型方法和其餘操做的強大技術,在其餘的庫或框架中都有使用,但仍是應該慎用。
除了咱們常常使用的fmt包是應用反射實現的以外,encoding/json、encoding/xml等包也是如此。
其實在一些Web框架中,將http請求參數綁定到模型中,在ORM框架中,將數據表查詢結果綁定到模型中,應用的都是反射技術。