Golang反射技術初始入門

反射是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

reflect.Type和reflect.Value

Go語言反射技術是由reflect包來實現,這個包主要定義了reflect.Type和reflect.Value兩個重要的類型。spa

reflect.Type

reflect.Type是一個接口,表明一個的具體類型,使用reflect.TypeOf()函數,能夠返回reflect.Type的實現,reflect.TypeOf()方法能夠接收任何類型的參數,以下:code

t := reflect.TypeOf(100)
fmt.Println(t)//int
複製代碼

reflect.Value

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框架中,將數據表查詢結果綁定到模型中,應用的都是反射技術。

相關文章
相關標籤/搜索