您好,登錄后才能下訂單哦!
這篇文章主要講解了“go語言有沒有反射”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“go語言有沒有反射”吧!
go語言有反射。Go語言提供了一種機制在運行時更新和檢查變量的值、調用變量的方法和變量支持的內在操作,但是在編譯時并不知道這些變量的具體類型,這種機制被稱為反射。Go語言中的反射是由reflect包提供支持的,它定義了兩個重要的類型Type和Value任意接口值在反射中都可以理解為由reflect.Type和reflect.Value兩部分組成。
Go語言提供了一種機制在運行時更新和檢查變量的值、調用變量的方法和變量支持的內在操作,但是在編譯時并不知道這些變量的具體類型,這種機制被稱為反射。反射也可以讓我們將類型本身作為第一類的值類型處理。
go語言中的反射
反射是指在程序運行期對程序本身進行訪問和修改的能力,程序在編譯時變量被轉換為內存地址,變量名不會被編譯器寫入到可執行部分,在運行程序時程序無法獲取自身的信息。
支持反射的語言可以在程序編譯期將變量的反射信息,如字段名稱、類型信息、結構體信息等整合到可執行文件中,并給程序提供接口訪問反射信息,這樣就可以在程序運行期獲取類型的反射信息,并且有能力修改它們。
C/C++語言沒有支持反射功能,只能通過 typeid 提供非常弱化的程序運行時類型信息;Java、C# 等語言都支持完整的反射功能;Lua、JavaScript 類動態語言,由于其本身的語法特性就可以讓代碼在運行期訪問程序自身的值和類型信息,因此不需要反射系統。
Go語言程序的反射系統無法獲取到一個可執行文件空間中或者是一個包中的所有類型信息,需要配合使用標準庫中對應的詞法、語法解析器和抽象語法樹(AST)對源碼進行掃描后獲得這些信息。
Go語言提供了 reflect 包來訪問程序的反射信息。
reflect 包
Go語言中的反射是由 reflect 包提供支持的,它定義了兩個重要的類型 Type 和 Value 任意接口值在反射中都可以理解為由 reflect.Type 和 reflect.Value 兩部分組成,并且 reflect 包提供了 reflect.TypeOf 和 reflect.ValueOf 兩個函數來獲取任意對象的 Value 和 Type。
反射的類型對象(reflect.Type)
在Go語言程序中,使用 reflect.TypeOf() 函數可以獲得任意值的類型對象(reflect.Type),程序通過類型對象可以訪問任意值的類型信息,下面通過示例來理解獲取類型對象的過程:
運行結果如下:package main
import (
"fmt"
"reflect"
)
func main() {
var a int
typeOfA := reflect.TypeOf(a)
fmt.Println(typeOfA.Name(), typeOfA.Kind())
}
代碼說明如下:
第 9 行,定義一個 int 類型的變量。
第 10 行,通過 reflect.TypeOf() 取得變量 a 的類型對象 typeOfA,類型為 reflect.Type()。
第 11 行中,通過 typeOfA 類型對象的成員函數,可以分別獲取到 typeOfA 變量的類型名為 int,種類(Kind)為 int。
反射的類型(Type)與種類(Kind)
在使用反射時,需要首先理解類型(Type)和種類(Kind)的區別。編程中,使用最多的是類型,但在反射中,當需要區分一個大品種的類型時,就會用到種類(Kind)。例如需要統一判斷類型中的指針時,使用種類(Kind)信息就較為方便。
1) 反射種類(Kind)的定義
Go語言程序中的類型(Type)指的是系統原生數據類型,如 int、string、bool、float32 等類型,以及使用 type 關鍵字定義的類型,這些類型的名稱就是其類型本身的名稱。例如使用 type A struct{} 定義結構體時,A 就是 struct{} 的類型。
種類(Kind)指的是對象歸屬的品種,在 reflect 包中有如下定義:
Map、Slice、Chan 屬于引用類型,使用起來類似于指針,但是在種類常量定義中仍然屬于獨立的種類,不屬于 Ptr。type A struct{} 定義的結構體屬于 Struct 種類,*A 屬于 Ptr。type Kind uint
const (
Invalid Kind = iota // 非法類型
Bool // 布爾型
Int // 有符號整型
Int8 // 有符號8位整型
Int16 // 有符號16位整型
Int32 // 有符號32位整型
Int64 // 有符號64位整型
Uint // 無符號整型
Uint8 // 無符號8位整型
Uint16 // 無符號16位整型
Uint32 // 無符號32位整型
Uint64 // 無符號64位整型
Uintptr // 指針
Float32 // 單精度浮點數
Float64 // 雙精度浮點數
Complex64 // 64位復數類型
Complex128 // 128位復數類型
Array // 數組
Chan // 通道
Func // 函數
Interface // 接口
Map // 映射
Ptr // 指針
Slice // 切片
String // 字符串
Struct // 結構體
UnsafePointer // 底層指針
)
2) 從類型對象中獲取類型名稱和種類
Go語言中的類型名稱對應的反射獲取方法是 reflect.Type 中的 Name() 方法,返回表示類型名稱的字符串;類型歸屬的種類(Kind)使用的是 reflect.Type 中的 Kind() 方法,返回 reflect.Kind 類型的常量。
下面的代碼中會對常量和結構體進行類型信息獲取。
運行結果如下:package main
import (
"fmt"
"reflect"
)
// 定義一個Enum類型
type Enum int
const (
Zero Enum = 0
)
func main() {
// 聲明一個空結構體
type cat struct {
}
// 獲取結構體實例的反射類型對象
typeOfCat := reflect.TypeOf(cat{})
// 顯示反射類型對象的名稱和種類
fmt.Println(typeOfCat.Name(), typeOfCat.Kind())
// 獲取Zero常量的反射類型對象
typeOfA := reflect.TypeOf(Zero)
// 顯示反射類型對象的名稱和種類
fmt.Println(typeOfA.Name(), typeOfA.Kind())
}
代碼說明如下:
第 17 行,聲明結構體類型 cat。
第 20 行,將 cat 實例化,并且使用 reflect.TypeOf() 獲取被實例化后的 cat 的反射類型對象。
第 22 行,輸出 cat 的類型名稱和種類,類型名稱就是 cat,而 cat 屬于一種結構體種類,因此種類為 struct。
第 24 行,Zero 是一個 Enum 類型的常量。這個 Enum 類型在第 9 行聲明,第 12 行聲明了常量。如沒有常量也不能創建實例,通過 reflect.TypeOf() 直接獲取反射類型對象。
第 26 行,輸出 Zero 對應的類型對象的類型名和種類。
指針與指針指向的元素
Go語言程序中對指針獲取反射對象時,可以通過 reflect.Elem() 方法獲取這個指針指向的元素類型,這個獲取過程被稱為取元素,等效于對指針類型變量做了一個*操作,代碼如下:
運行結果如下:package main
import (
"fmt"
"reflect"
)
func main() {
// 聲明一個空結構體
type cat struct {
}
// 創建cat的實例
ins := &cat{}
// 獲取結構體實例的反射類型對象
typeOfCat := reflect.TypeOf(ins)
// 顯示反射類型對象的名稱和種類
fmt.Printf("name:'%v' kind:'%v'\n", typeOfCat.Name(), typeOfCat.Kind())
// 取類型的元素
typeOfCat = typeOfCat.Elem()
// 顯示反射類型對象的名稱和種類
fmt.Printf("element name: '%v', element kind: '%v'\n", typeOfCat.Name(), typeOfCat.Kind())
}
代碼說明如下:
第 13 行,創建了 cat 結構體的實例,ins 是一個 *cat 類型的指針變量。
第 15 行,對指針變量獲取反射類型信息。
第 17 行,輸出指針變量的類型名稱和種類。Go語言的反射中對所有指針變量的種類都是 Ptr,但需要注意的是,指針變量的類型名稱是空,不是 *cat。
第 19 行,取指針類型的元素類型,也就是 cat 類型。這個操作不可逆,不可以通過一個非指針類型獲取它的指針類型。
第 21 行,輸出指針變量指向元素的類型名稱和種類,得到了 cat 的類型名稱(cat)和種類(struct)。
感謝各位的閱讀,以上就是“go語言有沒有反射”的內容了,經過本文的學習后,相信大家對go語言有沒有反射這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。