首頁 > 軟體

Go REFLECT Library反射型別詳解

2022-08-31 14:03:03

一、反射概述

反射是指程式在執行期間對程式本身進行存取和修改的能力。程式在編譯過程中變數會被轉換為記憶體地址,變數名不會被編譯器寫入到可執行部分。在程式執行時程式無法獲取自身的資訊。

在靜態語言中如 Java 可以在程式編譯期將變數的反射資訊,如欄位名稱、型別等資訊整合到可執行檔案中,並給程式提供介面存取反射資訊,這樣就可以在程式執行期獲取型別的反射資訊,並修改該它們。

對於動態語言來說如 Ruby 的動態特性相比靜態語言來說可以非常簡單的在程式執行時存取變數、方法或者物件資訊,也可以修改它們,甚至可以動態性可以讓程式自己構造並執行程式碼,這就是超程式設計。

Ruby 中的基礎類別(Object)包含了方法 methods、常數 constants 和範例變數instance_variable 的動態獲取。

puts String.method_defined?(:upcase) # 判斷是否定義了 upcase 方法
puts String.methods # 獲取所有方法
puts Math.const_get("PI") # 獲取常數
puts Math.const_set("PII", 1000) # 設定常數
puts Math.const_defined?(:P) # 判斷是否包含指定常數
puts Math.constants # 獲取所有常數

因此 Ruby 這裡動態直譯語言是反射系統的,但是 Go 作為一門靜態編譯型語言提供了 relect 標準庫存取程式的反射資訊。

Go 語言的反射系統無法獲取到一個可執行檔案空間中或者是一個包中所有型別資訊,需要配合使用標準庫中對應的詞法和語法解析器和抽象語法書對原始碼進行掃描後獲取這些資訊

二、反射型別物件

基本數型別的 反射型別物件

在 Go 中使用 reflect 標準庫下的 typeOf 函數可以獲取任意變數的反射型別物件,程式通過 反射型別物件 可以存取任意變數的型別資訊。

func main(){
   zulu := "stark"
   zuluType := reflect.TypeOf(zulu)
   fmt.Printf("zuluType 的型別為:%v,型別名為:%v,種類為:%vn", zuluType, zuluType.Name(), zuluType.Kind())
}

執行上述程式碼,輸出結果如下:

zuluType 的型別為:string,型別名為:string,種類為:string

TypeOf 函數返回一個 Type 介面,該介面包含非常多的方法

上述程式碼中的型別就是變數的資料型別,如基本資料型別中的 int、int64、float64、string、map、bool 以及 type 結構體型別等,型別名就是型別本身。

種類既 Kind 方法獲取的資訊是指物件歸屬的品種,在 reflect 庫中對物件歸屬的 Kind 做了定義

Kind 的範圍在如下列出的常數中

並在通過 String() 方法做了小寫的轉換,最終返回 Kind 為 string

Name 和 Kind 可以表示一個變數的 反射型別物件 的資訊。每種資料型別變數的 反射型別物件 的 Name 和 Kind 都是不同的。

參照資料型別的 反射型別物件

func main(){
   zulu := map[string]string{
      "name": "Stark",
      "address": "NYC",
   }
   zuluType := reflect.TypeOf(zulu)
   fmt.Printf("zuluType 的型別為:%v,型別名為:%v,種類為:%vn", zuluType, zuluType.Name(), zuluType.Kind())
}

執行上述程式碼,輸出結果如下:

zuluType 的型別為:map[string]string,型別名為:,種類為:map

Map、Array、Slice 和 Pointer 型別的 Name() 都為空字串

結構體的 反射型別物件

func main(){
   zulu := Zulu{"stark", 33}
   zuluType := reflect.TypeOf(zulu)
   fmt.Printf("zuluType 的型別為:%v,型別名為:%v,種類為:%vn", zuluType, zuluType.Name(), zuluType.Kind())
}
type Zulu struct {
   Name string
   Age int
}

執行上述程式碼,輸出結果如下:

zuluType 的型別為:main.Zulu,型別名為:Zulu,種類為:struct

結構體變數的 反射型別物件 的 Name 就是結構體的名字,種類為 struct 結構體

指標的 反射型別物件

func main(){
   zulu := Zulu{"stark", 33}
   // 定義一個指標
   zuluPtr := &zulu
   zuluType := reflect.TypeOf(zuluPtr)
   fmt.Printf("zuluType 的型別為:%v,型別名為:%v,種類為:%vn", zuluType, zuluType.Name(), zuluType.Kind())
}
type Zulu struct {
   Name string
   Age int
}

執行上述程式碼,輸出結果如下:

zuluType 的型別為:*main.Zulu,型別名為:,種類為:ptr

指標的 Name() 返回的也是空字串。

在 main 函數中增加程式碼

// 其餘程式碼保持不變,在 main 函數底部增加如下程式碼。
// 使用反射型別物件(Type)獲取原型別
zuluTypeElem := zuluType.Elem()
fmt.Printf("zuluTypeElem 的型別為:%v,型別名為:%v,種類為:%vn", zuluTypeElem, zuluTypeElem.Name(), zuluTypeElem.Kind())

執行上述的程式碼,輸出結果如下:

zuluType 的型別為:*main.Zulu,型別名為:,種類為:ptr
zuluTypeElem 的型別為:main.Zulu,型別名為:Zulu,種類為:struct

也就是說我們通過一個結構體指標獲取了一個反射型別,在通過反射型別獲取到原結構體

Go 中對指標獲取 反射型別物件 之後,可以通過獲取的 反射型別物件Elem 方法獲取指標所執行的元素的型別,這個過程被稱為取元素,就相當於對指標執行了 * 操作。

以上就是Go REFLECT Library反射型別詳解的詳細內容,更多關於Go REFLECT Library反射型別的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com