一篇文章教會你Go語言基礎(chǔ)之反射
前言
Hey,大家好呀,我是碼農(nóng),星期八!,我們以前學的呀,都屬于正向定義變量,正向開發(fā)!
但是有沒有什么辦法能反著來呢?根據(jù)變量獲取類型等操作。
一起來看看Go的反射吧!!!
什么是反射
反射,嗯...,就是反著的意思唄,就是把東西反過來。
比如這樣的一個很簡單的代碼。
- var a int = 3
 - fmt.Println(a)
 
我們當然知道a變量是int類型,但是反過來想,程序是怎么知道a是int類型呢???
這時候,就需要用到反射了。
示例代碼
- v := reflect.TypeOf(a)
 - fmt.Println(v)
 
兩次代碼綜合一塊執(zhí)行結(jié)果
第二次的第2行代碼,成功的將變量a還原出了int類型。
什么???你為我有什么用???,嗯。。。實話實說,用的不是太多,但是必須要會的。
反射(reflect包)
在Go中,任何變量,都有具體類型和具體值,就像var a int = 3,具體類型就是int,具體值就是3。
所以,變量的具體類型歸屬在reflect.Type,變量的具體值歸屬在reflect.Value。
并且Go的提供了
- reflect.TypeOf獲取具體類型。
 - reflect.ValueOf獲取具體值。
 
TypeOf
TypeOf方法可以獲取變量的具體類型。
有一個這樣的需求,定義一個函數(shù),可以接收任意類型數(shù)據(jù),通過反射打印變量類型。
示例代碼
函數(shù)
- func reflectType(x interface{}) {
 - v := reflect.TypeOf(x)
 - fmt.Printf("你傳入的變量類型是:%v\n",v)
 - }
 
main
- func main() {
 - var a int = 666
 - var b float64 = 3.14
 - var c string = "hello world"
 - var d [3]int = [3]int{1,2,6}
 - var e []int = []int{1,2,6,88}
 - var f map[string]interface{} = map[string]interface{}{
 - "Name":"張三",
 - "Age":18,
 - }
 - reflectType(a)
 - reflectType(b)
 - reflectType(c)
 - reflectType(d)
 - reflectType(e)
 - reflectType(f)
 - }
 
執(zhí)行結(jié)果
通過reflect.TypeOf方法,完美解決上述需求。
TypeOf 的Name和Kind
這個是啥意思呢??這個在結(jié)構(gòu)體中比較好體現(xiàn)。
簡答來說就是TypeOf返回的太籠統(tǒng)了,還有更加細化的類型,通過這倆屬性獲取。
示例代碼
函數(shù)
- func reflectType(x interface{}) {
 - v := reflect.TypeOf(x)
 - fmt.Printf("你傳入的變量類型是:%v | Name:%v | Kind:%v\n", v, v.Name(), v.Kind())
 - }
 
結(jié)構(gòu)體
- type Student struct {
 - Name string
 - Age int
 - }
 
main
- func main() {
 - var a int
 - var b *int
 - var c []int
 - var d map[string]interface{}
 - var e Student
 - reflectType(a)
 - reflectType(b)
 - reflectType(c)
 - reflectType(d)
 - reflectType(e)
 - }
 
執(zhí)行結(jié)果
總結(jié)
經(jīng)過對比,會發(fā)現(xiàn)幾個特殊問題。
如果變量是指針類型,Name為空,Kind是ptr。
如果變量是引用類型(切片和map)類型,Name為空,只有Kind。
如果變量是結(jié)構(gòu)體,Name是結(jié)構(gòu)體名,Kind是struct。
ValueOf
TypeOf只能反過來獲取變量的具體類型,但是并不能獲取具體值,這就有點不太厚道了。
所以ValueOf就來解決這個問題了,但是ValueOf牛叉的是,它里面還包括了變量類型。
注:ValueOf和TypeOf的Kind屬性返回內(nèi)容是一摸一樣的。
需求:定義一個函數(shù),可以接收任意類型,通過反射得出變量類型和變量值。
函數(shù)
- func reflectType(x interface{}) {
 - v := reflect.ValueOf(x)
 - k := v.Kind()
 - switch k {
 - case reflect.Int:
 - fmt.Printf("我是Int類型,我的值是%v\n",v.Int())
 - case reflect.Slice:
 - fmt.Printf("我是切片類型,我的值是%v\n",v.Slice(1,2))
 - case reflect.Map:
 - fmt.Printf("我是切片類型,我的值是%v\n",v.MapKeys())
 - //case :可以繼續(xù)case下去
 - }
 - }
 
main
- func main() {
 - var a int = 1
 - var c []int = []int{1, 5, 7, 19}
 - var d map[string]interface{} = map[string]interface{}{
 - "Name": "你好",
 - "Age": 18,
 - }
 - var e Student
 - reflectType(a)
 - reflectType(c)
 - reflectType(d)
 - reflectType(e)
 - }
 
執(zhí)行結(jié)果
通過反射設(shè)置值
反射還有一個用途,就是動態(tài)的修改變量值,可能你暫時體會不到,但是語法還是要學的。
通過反射設(shè)置值,需要用到Elem方法,并且傳入的必須是指針。
示例代碼
函數(shù)
- func reflectSetValue(x interface{}) {
 - v := reflect.ValueOf(x)
 - //kind也必須是Elem調(diào)用
 - var k = v.Elem().Kind()
 - switch k {
 - case reflect.Int:
 - //反射修改必須通過Elem
 - v.Elem().SetInt(200)
 - }
 - }
 
main
- func main() {
 - var a int = 10
 - fmt.Printf("a的值:%v\n", a)
 - //反射修改值傳入的必須是地址
 - reflectSetValue(&a)
 - fmt.Printf("a的值:%v\n", a)
 - }
 
執(zhí)行結(jié)果
總結(jié)
上述我們學習了Go基礎(chǔ)反射的TypeOf,TypeOf的Name和Kind,ValueOf,通過反射設(shè)置值。
其中Kind在Type和ValueOf中都有,通常情況下TypeOf和ValueOf一起使用效果更佳!
反射這一塊,可能不是那么好理解,一定要多多下功夫!堅持!!
如果在操作過程中有任何問題,記得下面留言,我們看到會第一時間解決問題。我是碼農(nóng)星期八,如果覺得還不錯,記得動手點贊一下哈。感謝你的觀看。
本文轉(zhuǎn)載自微信公眾號「Go語言進階學習」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系Go語言進階學習公眾號。





















 
 
 



 
 
 
 