1、反射可以在運行時 動態(tài)獲取變量的各種信息 ,比如變量的類型、類別;
創(chuàng)新互聯(lián)建站專注于洪山網(wǎng)站建設服務及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗。 熱誠為您提供洪山營銷型網(wǎng)站建設,洪山網(wǎng)站制作、洪山網(wǎng)頁設計、洪山網(wǎng)站官網(wǎng)定制、微信小程序開發(fā)服務,打造洪山網(wǎng)絡公司原創(chuàng)品牌,更為您提供洪山網(wǎng)站排名全網(wǎng)營銷落地服務。
2、如果是結(jié)構(gòu)體變量,還可以獲取到結(jié)構(gòu)體本身的信息(包括結(jié)構(gòu)體的字段、方法);
3、通過反射,可以修改 變量的值 ,可以調(diào)用關聯(lián)的方法;
4、使用反射,需要import " reflect ".
5、示意圖:
1、不知道接口調(diào)用哪個函數(shù),根據(jù)傳入?yún)?shù)在運行時確定調(diào)用的具體接口,這種需要對函數(shù)或方法反射。
例如以下這種橋接模式:
示例第一個參數(shù)funcPtr以接口的形式傳入函數(shù)指針,函數(shù)參數(shù)args以可變參數(shù)的形式傳入,bridge函數(shù)中可以用反射來動態(tài)執(zhí)行funcPtr函數(shù)。
1、reflect.TypeOf(變量名),獲取變量的類型,返回reflect.Type類型。
2、reflect.ValueOf(變量名),獲取變量的值,返回reflect.Value類型reflect.Value是一個結(jié)構(gòu)體類型。
3、變量、interface{}和reflect.Value是可以互相轉(zhuǎn)換的,這點在實際開發(fā)中,會經(jīng)常使用到。
1、reflect.Value.Kind,獲取變量的 類別(Kind) ,返回的是一個 常量 。在go語言文檔中:
示例如下所示:
輸出如下:
Kind的范疇要比Type大。比如有Student和Consumer兩個結(jié)構(gòu)體,他們的 Type 分別是 Student 和 Consumer ,但是它們的 Kind 都是 struct 。
2、Type是類型,Kind是類別,Type和Kind可能是相同的,也可能是不同的。
3、通過反射可以在讓 變量 在 interface{} 和 Reflect.Value 之間相互轉(zhuǎn)換,這點在前面畫過示意圖。
4、使用反射的方式來獲取變量的值(并返回對應的類型),要求數(shù)據(jù)類型匹配,比如x是int,那么久應該使用reflect.Value(x).Int(),而不能使用其它的,否則報panic。
如果是x是float類型的話,也是要用reflect.Value(x).Float()。但是如果是struct類型的話,由于type并不確定,所以沒有相應的方法,只能 斷言。
5、通過反射的來修改變量,注意當使用SetXxx方法來設置需要通過對應的指針類型來完成,這樣才能改變傳入的變量的值,同時需要使用到reflect.Value.Elem()方法。
輸出num=20,即成功使用反射來修改傳進來變量的值。
6、reflect.Value.Elem()應該如何理解?
import (
"fmt"
"reflect"
)
func reflecType(x interface{}){
v := reflect.TypeOf(x)
fmt.Println("type:%v\n", v)
fmt.Println("type name:%v , rtpe kind:%v \n", v.getName(), v.getType())
}
type Cat struct{}
//通過反射設置變量的值
func reflectSetValue1(x interface{}){
v := reflect.ValueOf(x)
if v.Kind() == reflect.Int64{
v.SetInt(200) //修改的是副本, reflect 包會引發(fā)panic
}
}
//通過反射設置變量的值
func reflectSetValue2(x interface{}){
v := reflect.ValueOf(x)
//反射中使用Elem()獲取指針對應的值
if v.Elem().Kind() == reflect.Int64{
v.Elem().SetInt(200)
}
}
func main(){
var a float32 = 3.14
reflectType(a) //type name:float32 type kind:float32
var b int64 = 100
reflectType(b) // type name :int64 type kind :int64
var c = Cat{}
reflectType(c) // type name :Cat type kind :struct
reflectSetValue1(b)
fmt.Println(b) //依然為100
reflectSetValue2(b)
}
這是它的優(yōu)點,因為編譯器在編譯時不去確定你傳的到底是什么類型,你傳一個string,它能接收,你傳一個對象struct,它也能接收,它只有一個要求,實現(xiàn)我要求實現(xiàn)的方法!
既然interface是不限定類型,是通用類型,這是一種開放表現(xiàn),這種開放怎么實現(xiàn)的呢?方法就是不去檢驗你的類型,既然不檢驗那也不去記錄你的類型?。。。∽⒁鈏nterface不記錄你的類型,所以不管你是string,struct,int,我都不管,我都不記錄,我只記錄你的地址,結(jié)果是編譯器在編譯時也不知道你是什么類型,你有什么字段!
但是現(xiàn)在有一個問題,編譯器也沒辦法確定一個interface以前是什么類型?。ň幾g時)這就是因果關系:為了達到通用,interface不做確定工作,結(jié)果就是interface也不知道以前的類型。
一個類型轉(zhuǎn)接口的過程,就是放棄自我類型的過程,變成了沒有類型。
這樣做有什么好處呢,很顯然是:通用,如果把一個函數(shù)的傳入?yún)?shù)設置為空接口(interface{}),那么任何類型當做參數(shù)都能夠調(diào)用該接口,最好的例子就是:
它就是一個很標準的例子,println傳入?yún)?shù)可以是任何類型,都能打印出它的值。
當然你可以說你記得,因為是你把它轉(zhuǎn)換成interface,你理所當然的記得,可編譯器不知道啊,interface不包含類型,也就是說你沒有讓它去記錄,所以它不知道。
針對這個問題,go語言給了一個解決方案,斷言,當將一個interface轉(zhuǎn)換成它原來類型的時候,在它后面指明它的原來類型,這樣編譯器就知道該按照什么類型去解析了。(其實說白了,這就是通過人的記憶,編譯器不知道是什么類型,你告訴編譯器就可以了)
斷言其實是先獲取interface的動態(tài)類型,然后與你指定的類型做判斷,如果一致,將它轉(zhuǎn)換成你指定的類型。如果不知道動態(tài)類型,可以看這篇文章:
從報錯可以看出, 不能直接轉(zhuǎn)換,需要對接口先進行斷言
通常情況下,一個變量在確定類型的情況下編譯器知道他有哪些功能(注意,這里是針對編譯時),比如一個int類型,編譯器在編譯時知道能對他加減int,不能加減float,如果你這么做我就給你報錯。一個struct包含哪些字段,不包含哪些字段,我定義一個user結(jié)構(gòu)體,里面只有name和age兩個字段,那么你只能取我這兩字段的值,你如果取height,我就給你報錯。
這些都是正常情況下的,但是對于一個接口呢,編譯器會變成瞎子!在編譯的時候它不知道你原來是什么類型,所以它也沒法確定你包含什么字段,同樣是之前那個user結(jié)構(gòu)體,當把它轉(zhuǎn)換成接口以后,編譯器就對它的類型一無所知了,你獲取name字段,這有接口有沒有呢?編譯器不知道!你請求height字段,這個泛型有沒有呢?編譯器仍然不知道。所以你編譯時不能修改接口里的數(shù)據(jù),既然編譯時 不能修改,那就只能在運行時修改了。
這個時候就該反射登場了,它能夠在運行時修改接口的數(shù)據(jù),通過追根溯源,獲取接口底層的實際數(shù)據(jù)和類型,讓你能夠?qū)涌诘脑磾?shù)據(jù)進行操作。
換一種大白話的說法,反射就是刨根問底,獲取這個接口究竟是怎么產(chǎn)生的,因為哪怕一個類型轉(zhuǎn)變成接口時放棄了自己的類型,但是它的本質(zhì)不會變的,就像趙本山的小品里所說:小樣,別以為你脫掉馬甲我就不認識你了!對,它的底層里仍然存儲了它的數(shù)據(jù)類型,只是藏的比較深,一般手段拿不到,但我們?nèi)匀荒軌蛲ㄟ^反射(這個包根問底的工具)來確定你究竟包含哪些字段和值,確定你究竟是蛇還是脫了馬甲的烏龜!
網(wǎng)站欄目:go語言94反射教程 go語言反射原理
網(wǎng)站路徑:http://jinyejixie.com/article4/dodohoe.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供虛擬主機、網(wǎng)站排名、靜態(tài)網(wǎng)站、小程序開發(fā)、企業(yè)網(wǎng)站制作、網(wǎng)站內(nèi)鏈
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)