中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Golang中的反射規則是什么

發布時間:2022-12-15 09:44:09 來源:億速云 閱讀:124 作者:iii 欄目:編程語言

這篇文章主要介紹“Golang中的反射規則是什么”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“Golang中的反射規則是什么”文章能幫助大家解決問題。

簡單來看反射是什么

簡單來看,反射就是在程序運行時期對程序本身進行訪問和修改的能力,例如在程序運行時,可以修改程序的字段名稱,字段值,還可以給程序提供接口訪問的信息等等

這是 Go 語言中提供的一種機制,我們可以在 Go 語言公共庫中可以看到很多關于 reflect 的使用位置

例如常用的 fmt 包,常用的 json 序列化和反序列化,自然前面我們說到的 gorm 庫自然也是使用了反射的

Golang中的反射規則是什么

Golang中的反射規則是什么

可是我們一般為什么要使用反射呢?

根據反射的能力,自然是因為我們提供的接口并不知道傳入的數據類型會是什么樣的, 只有當程序運行的時候才知道具體的數據類型

但是我們編碼的時候又期望去校驗程序運行時傳入的類型會是什么樣的(例如 json 的序列化)并對其這種具體的數據進行操作,這個時候,咱們就需要用到反射的能力了

所以對于使用到反射的地方,你都能看到 interface{} 是不是就不奇怪了呢?

正是因為不確定傳入的數據類型會是什么樣的,所以才設計成 interface{} 

先關注反射的規則

首先關注反射的三個重要的定律,知道規則之后,我們按照規則玩就不會有什么問題,只有當我們不清楚規則,總是觸發條款的時候,才會出現奇奇怪怪的問題

  • 反射是可以將 接口類型的變量 轉換成 反射類型的對象

  • 反射可以將 反射類型的對象 轉換成 接口類型的變量

  • 我們在運行時要去修改的 反射類型的對象 ,那么要求這個對象對應的值是要可寫的

對于上述 3 個規則也是比較好理解,還記的之前我們說過的 unsafe 包里面的指針嗎?

都是將我們常用的數據類型,轉換成包(例如 unsafe包,或者 reflect 包)里面的指定數據類型,然后再按照包里面的規則進行修改數據

相當于,換個馬甲,就可以進行不同的操作了

關注使用案例并靈活運用

一般咱們先會基本的應用,再去研究他的原理,研究他為什么可以這樣用,慢慢的才能理解的更加深刻

對于定律一,將 接口類型的變量 轉換成 反射類型的對象

實際上此處說的 接口類型的變量 我們可以傳入任意數據類型的變量,例如 int, float, string ,map, slice, struct 等等

反射類型的對象 這里就可以理解成 reflect 反射包中的 reflect.Type reflect.Value 對象,可以通過 reflect 包中提供的 TypeOfValueOf 函數得到

其中 reflect.Type 實際上是一個 interface ,他里面包含了各種接口需要進行實現,它里面提供了關于類型相關的信息

其中如下圖可以查看到 reflect.Type 的所有方法,其中

  • 綠色的 是所有數據類型都是可以調用的

  • 紅色的是 函數類型數據可以調用的

  • 黑色的是 Map,數組 Array,通道 Chan,指針 Ptr 或者 切片Slice 可以調用的

  • 藍色的是結構體調用的

  • 黃色的是通道 channel 類型調用的

Golang中的反射規則是什么

reflect.Value 實際上是一個 struct,根據這個 struct 還關聯了一組方法,這里面存放了數據類型和具體的數據,通過查看其數據結構就可以看出

type Value struct {
   typ *rtype
   ptr unsafe.Pointer
   flag
}

看到此處的 unsafe.Pointer 是不是很熟悉,底層自然就可以將 unsafe.Pointer 轉換成 uintptr,然后再修改其數據后,再轉換回來,對于 Go 指針不太熟悉的可以查看這篇文章:

  • GO 中的指針?

寫一個簡單的 demo 就可以簡單的獲取到變量的數據類型和值

func main() {   var demoStr string = "now reflect"
   fmt.Println("type:", reflect.TypeOf(demoStr))
   fmt.Println("value:", reflect.ValueOf(demoStr))
}

Golang中的反射規則是什么

對于定律二,將 反射類型的對象 轉換成 接口類型的變量

我們可以通過將 reflect.Value 類型轉換成我們具體的數據類型,因為 reflect.Value 中有對應的 typ *rtype 以及 ptr unsafe.Pointer

例如我們可以 通過 reflect.Value 對象的 interface() 方法來處理

Golang中的反射規則是什么

func main() {   var demoStr string = "now reflect"
   fmt.Println("type:", reflect.TypeOf(demoStr))
   fmt.Println("value:", reflect.ValueOf(demoStr))   var res string
   res = reflect.ValueOf(demoStr).Interface().(string)
   fmt.Println("res == ",res)
}

Golang中的反射規則是什么

對于定律三,修改反射類型的對象

首先我們看上書的 demo 代碼,傳入 TypeOfValueOf 的變量實際上也是一個拷貝,那么如果期望在反射類型的對象中修改其值,那么就需要拿到具體變量的地址然后再進行修改,前提是這個變量是可寫的

舉個例子你就能明白

func main() {
   var demoStr string = "now reflect"
   v := reflect.ValueOf(demoStr)
   fmt.Println("is canset ", v.CanSet())
   //v.SetString("hello world")   // 會panic
   }

Golang中的反射規則是什么

可以先調用 reflect.Value 對象的 CanSet 查看是否可寫,如果是可寫的,我們再寫,如果不可寫就不要寫了,否則會 panic

Golang中的反射規則是什么

那么傳入變量的地址就可以修改了??

Golang中的反射規則是什么

傳入地址的思路沒有毛病,但是我們去設置值的方式有問題,因此也會出現上述的 panic 情況

此處仔細看能夠明白,反射的對象 v 自然是不可修改的,我們應該找到 reflect.Value 里面具體具體的數據指針,那么才是可以修改的,可以使用 reflect.Value Elem 方法

Golang中的反射規則是什么

稍微復雜一點的

看上了上述案例可能會覺得那么簡單的案例,一演示就 ok,但是工作中一用就崩潰,那自然還是沒有融會貫通,說明還沒有消化好,再來一個工作中的例子

  • 一個結構體里面有 map,map 中的 key 是 string,value 是 []string

  • 需求是訪問 結構體中 hobby 字段對應的 map key 為 sport 的切片的第1 個元素,并將其修改為 hellolworld

type RDemo struct {
   Name  string
   Age   int
   Money float32
   Hobby map[string][]string
}

func main() {
   tmp := &RDemo{
      Name:  "xiaomiong",
      Age:   18,
      Money: 25.6,
      Hobby: map[string][]string{
         "sport": {"basketball", "football"},
         "food":  {"beef"},
      },
   }

   v := reflect.ValueOf(tmp).Elem()  // 拿到結構體對象
   h := v.FieldByName("Hobby")    // 拿到 Hobby 對象
   h2 := h.MapKeys()[0]    // 拿到 Hobby 的第 0 個key
   fmt.Println("key1 name == ",h2.Interface().(string))

   sli := h.MapIndex(h2)    // 拿到 Hobby 的第 0 個key對應的對象
   str := sli.Index(1)      // 拿到切片的第 1 個對象
   fmt.Println(str.CanSet())

   str.SetString("helloworld")
   fmt.Println("tmp == ",tmp)
}

Golang中的反射規則是什么

可以看到上述案例運行之后有時可以運行成功,有時會出現 panic 的情況,相信細心的 xdm 就可以看出來,是因為 map 中的 key 是 無序的導致的,此處也提醒一波,使用 map 的時候要注意這一點

看上述代碼,是不是就能夠明白咱們使用反射去找到對應的數據類型,然后按照數據類型進行處理數據的過程了呢

有需要的話,可以慢慢的去熟練反射包中涉及的函數,重點是要了解其三個規則,對象轉換方式,訪問方式,以及數據修改方式

反射原理

那么通過上述案例,可以知道關于反射中數據類型和數據指針對應的值是相當重要的,不同的數據類型能夠用哪些函數這個需要注意,否則用錯直接就會 panic

TypeOf

來看 TypeOf 的接口中涉及的數據結構

Golang中的反射規則是什么

Golang中的反射規則是什么

在 reflect 包中 rtype 是非常重要的,Go 中所有的類型都會包含這個結構,所以咱們反射可以應用起來,結構如下

// rtype must be kept in sync with ../runtime/type.go:/^type._type.
type rtype struct {
   size       uintptr
   ptrdata    uintptr
   hash       uint32 
   tflag      tflag
   align      uint8
   fieldAlign uint8
   kind       uint8
   equal     func(unsafe.Pointer, unsafe.Pointer) bool
   gcdata    *byte 
   str       nameOff
   ptrToThis typeOff
}

其中可以看到此處的 rtype 的結構保持和 runtime/type.go 一致 ,都是關于數據類型的表示,以及對應的指針,關于這一塊的說明和演示可以查看文末的 interface{} 處的內容

ValueOf

ValueOf 的源碼中,我們可以看到,重要的是 emptyInterface 結構

Golang中的反射規則是什么

Golang中的反射規則是什么

Golang中的反射規則是什么

// emptyInterface is the header for an interface{} value.type emptyInterface struct {
   typ  *rtype
   word unsafe.Pointer
}復制代碼

emptyInterface 結構中有 rtype 類型的指針, word 自然是對應的數據的地址了

reflect.Value 對象中的方法也是非常的多,用起來和上述說到的 reflect.Type 接口中的功能類似

關于源碼中涉及到的方法,就不再過多的贅述了,更多的還是需要自己多多實踐才能體會的更好

殊不知,此處的 reflect.Value 也是可以轉換成 reflect.Type ,可以查看源碼中 reflect\value.gofunc (v Value) Type() Type {

其中   reflect.Value  ,reflect.Type ,和任意數據類型 可以相互這樣來轉換

如下圖:

Golang中的反射規則是什么

關于“Golang中的反射規則是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

芦山县| 册亨县| 安康市| 普兰县| 新郑市| 政和县| 义乌市| 霍林郭勒市| 比如县| 沅陵县| 宜兴市| 高碑店市| 花莲县| 南部县| 辉县市| 尉犁县| 乐山市| 同德县| 海城市| 彭山县| 贡觉县| 阿克陶县| 将乐县| 万全县| 安图县| 丰都县| 崇明县| 泉州市| 依兰县| 司法| 克拉玛依市| 五峰| 拉萨市| 阿拉尔市| 白银市| 紫阳县| 西林县| 仙桃市| 奎屯市| 沁阳市| 喀喇|