Go 反射:根據類型建立對象-第一部分(原始類型)

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。> 這是關於在 Go 中根據類型建立對象的部落格系列兩部分的第一部分。這部分討論原始類型的對象建立 ![](https://raw.githubusercontent.com/studygolang/gctt-images/master/go-reflect/cover1.png)Go 中的 reflect 包提供了根據執行過程中對象的類型來改變程式控制流程的 API。 reflect 包提供了兩個重要的結構 - Type 和 Value。 Type 是一個 Go 中任何類型的代表。換句話說,它可以被用於編碼任何 Go 類型(例如:int , string , bool , myCustomType 等等)。Value 是一個 Go 中任何值的代表。換句話說,它可以被用於編碼、操作任何 Go 的值。## 類型與類別(Types 和 Kinds)Go 中有一個隱形、鮮為人知的,使得 Type 和 Kind 含義有差別的公約。這種差別可以通過一個例子理解一下。看一下這個結構:```gotype example struct {field1 type1field2 type2}```這個結構體的一個對象的 type 應該是 example。而這個對象的 kind 應該是 struct。這裡的 Kind 可以被看成一個 Type 的 Type。> 在 Go 裡所有 structs 都是相同的 kind,但不是相同的 Type 像 Pointer、Array、Slice、Map 等等複雜類型,使得 type 和 kind 的含義產生了這樣的差異。 相比之下,像 int、float、string 等等原始類型,並沒有產生 type 和 kind 含義上的差別。換句話說,一個 int 變數的 kind 是 int。一個 int 變數的 type 也是 int。## 根據類型建立對象為了根據一個類型標籤(type signature)建立一個對象,這個對象的 type 和 kind 都是必要的。從這裡開始,當我用到 ‘type signature’ 這個術語時,我的意思就是 Go 裡的 reflect.Type 類型的對象。### 根據原始類型建立原始對象原始對象可以根據它們的 type signature,通過使用它們的 Zero 值被建立。> 一個類型的 Zero 值是指一個該類型、沒有初始化的對象的值這是一個 Go 中所有原始類型的列表:```BoolIntInt8Int16Int32Int64UintUint8Uint16Uint32Uint64UintptrFloat32Float64Complex64Complex128StringUnsafePointer```通過使用 reflect.Zero 函數,可以建立原始類型的對象```gofunc CreatePrimitiveObjects(t reflect.Type) reflect.Value {return reflect.Zero(t)}```這裡將建立一個期望的對象,並返回一個擁有相應 Zero 值的 reflect.Value 對象。為了讓這個對象可以使用,需要將它的值提取一下。對於不同的原始類型,相應對象的值可以採用相應適合的方法來提取。### 提取整數值在 Go 裡有 5 種整數類型:```IntInt8Int16Int32Int64```Int 類型表示平台定義的預設整型大小。另外 4 種類型分別是 8,16,32,64(bit單位)大小的整型。為了獲得每種不同的整數類型,reflect.Value 對象對應的整數需要被轉換成相應的整數類型。這裡是如何提取 int32 類型:```go// Extract Int32func extractInt32(v reflect.Value) (int32, error) {// 譯註:原文是 reflect.Kind() != reflect.Int32,這次錯誤的。if v.Kind() != reflect.Int32 {return int32(0), errors.New("Invalid input")}var intVal int64intVal = v.Int()return int32(intVal), nil}```值得注意的是:reflect.Int() 會返回 int64 類型。這是因為 int64 類型可以編碼成其他所有整數類型。這裡是剩餘其他整數類型的提取:```go// Extract Int64func extractInt64(v reflect.Value) (int64, error) {// 譯註:原文是 reflect.Kind() != reflect.Int64,這次錯誤的。if v.Kind() != reflect.Int64 {return int64(0), errors.New("Invalid input")}var intVal int64intVal = v.Int()return intVal, nil}// Extract Int16func extractInt16(v reflect.Value) (int16, error) {// 譯註:原文是 reflect.Kind() != reflect.Int16,這次錯誤的。if v.Kind() != reflect.Int16 {return int16(0), errors.New("Invalid input")}var intVal int64intVal = v.Int()return int16(intVal), nil}// Extract Int8func extractInt8(v reflect.Value) (int8, error) {// 譯註:原文是 reflect.Kind() != reflect.Int8,這次錯誤的。if v.Kind() != reflect.Int8 {return int8(0), errors.New("Invalid input")}var intVal int64intVal = v.Int()return int8(intVal), nil}// Extract Intfunc extractInt(v reflect.Value) (int, error) {// 譯註:原文是 reflect.Kind() != reflect.Int,這次錯誤的。if v.Kind() != reflect.Int {return int(0), errors.New("Invalid input")}var intVal int64intVal = v.Int()return int(intVal), nil}```### 提取布爾值布爾值在 reflect 包中用常量 Bool 表示。它們可以通過使用 Bool() 方法,從 reflect.Value 對象中提取出來:```go// Extract Boolfunc extractBool(v reflect.Value) (bool, error) {// 譯註:原文是 reflect.Kind() != reflect.Bool,這次錯誤的。if v.Kind() != reflect.Bool {return false, errors.New("Invalid input")}return v.Bool(), nil}```### 提取不帶正負號的整數在 Go 中有 5 種不帶正負號的整數類型:```UintUint8Uint16Uint32Uint64```Uint 類型表示平台定義的預設無符號整型大小。另外 4 種類型分別是 8,16,32,64(bit單位)大小的無符號整型。為了獲得每種不同的不帶正負號的整數類型,reflect.Value 對象對應的不帶正負號的整數需要被轉換成相應的不帶正負號的整數類型。這裡是如何提取 Uint32 類型:```go// Extract Uint32func extractUint32(v reflect.Value) (uint32, error) {// 譯註:原文是 reflect.Kind() != reflect.Uint32,這次錯誤的。if v.Kind() != reflect.Uint32 {return uint32(0), errors.New("Invalid input")}var uintVal uint64uintVal = v.Uint()return uint32(uintVal), nil}```值得注意的是:reflect.Uint() 會返回 uint64 類型。這是因為 uint64 類型可以編碼成其他所有整數類型。這裡是剩餘其他不帶正負號的整數類型的提取:```go// Extract Uint64func extractUint64(v reflect.Value) (uint64, error) {// 譯註:原文是 reflect.Kind() != reflect.Uint64,這次錯誤的。if v.Kind() != reflect.Uint64 {return uint64(0), errors.New("Invalid input")}var uintVal uint64uintVal = v.Uint()return uintVal, nil}// Extract Uint16func extractUint16(v reflect.Value) (uint16, error) {// 譯註:原文是 reflect.Kind() != reflect.Uint16,這次錯誤的。if v.Kind() != reflect.Uint16 {return uint16(0), errors.New("Invalid input")}var uintVal uint64uintVal = v.Uint()return uint16(uintVal), nil}// Extract Uint8func extractUint8(v reflect.Value) (uint8, error) {// 譯註:原文是 reflect.Kind() != reflect.Uint8,這次錯誤的。if v.Kind() != reflect.Uint8 {return uint8(0), errors.New("Invalid input")}var uintVal uint64uintVal = v.Uint()return uint8(uintVal), nil}// Extract Uintfunc extractUint(v reflect.Value) (uint, error) {// 譯註:原文是 reflect.Kind() != reflect.Uint,這次錯誤的。if v.Kind() != reflect.Uint {return uint(0), errors.New("Invalid input")}var uintVal uint64uintVal = v.Uint()return uint(uintVal), nil}```### 提取浮點數在 Go 中有 2 種浮點數類型:```Float32Float64```Float32 類型表示 32bit 大小的浮點數。 Float64 類型表示 64bit 大小的浮點數。為了獲得每種不同的浮點數類型,reflect.Value 對象對應的浮點數需要被轉換成相應的浮點數類型。這裡是如何提取 Float32 類型:```go// Extract Float32func extractFloat32(v reflect.Value) (float32, error) {// 譯註:原文是 reflect.Kind() != reflect.Float32,這次錯誤的。if v.Kind() != reflect.Float32 {return float32(0), errors.New("Invalid input")}var floatVal float64floatVal = v.Float()return float32(floatVal), nil}```值得注意的是:reflect.Float() 會返回 float64 類型。這是因為 float64 類型可以編碼成其他所有浮點數類型。這裡是如何提取 64-bit 的浮點數值:```go// Extract Float64func extractFloat64(v reflect.Value) (float64, error) {// 譯註:原文是 reflect.Kind() != reflect.Float64,這次錯誤的。if v.Kind() != reflect.Float64 {return float64(0), errors.New("Invalid input")}var floatVal float64floatVal = v.Float()return floatVal, nil}```### 提取複數值在 Go 中有 2 種複數類型:```Complex64Complex128```Complex64 類型表示 64bit 大小的複數。Complex128 類型表示 128bit 大小的複數。為了獲得每種不同的複數類型,reflect.Value 對象對應的複數需要被轉換成相應的複數類型。這裡是如何提取 Complex64 類型:```go// Extract Complex64func extractComplex64(v reflect.Value) (complex64, error) {// 譯註:原文是 reflect.Kind() != reflect.Complex64,這次錯誤的。if v.Kind() != reflect.Complex64 {return complex64(0), errors.New("Invalid input")}var complexVal complex128complexVal = v.Complex()return complex64(complexVal), nil}```值得注意的是:reflect.Complex() 會返回 complex128 類型。這是因為 complex128 類型可以編碼成其他所有複數類型。這裡是如何提取 128-bit 的複數值:```go// Extract Complex128func extractComplex128(v reflect.Value) (complex128, error) {// 譯註:原文是 reflect.Kind() != reflect.Complex128,這次錯誤的。if v.Kind() != reflect.Complex128 {return complex128(0), errors.New("Invalid input")}var complexVal complex128complexVal = v.Complex()return complexVal, nil}```### 提取字串值在 reflect 包中,字串值用常量 String 表示。它們可以通過使用 String() 方法,從 reflect.Value 對象中提取出來:這裡是如何提取 String 類型:```go// Extract Stringfunc extractString(v reflect.Value) (string, error) {// 譯註:原文是 reflect.Kind() != reflect.String,這次錯誤的。if v.Kind() != reflect.String {return "", errors.New("Invalid input")}return v.String(), nil}```### 提取指標值在 Go 中,有 2 種指標類型:```UintptrUnsafePointer```Uintptr 和 UnsafePointer 其實是程式記憶體中代表一個虛擬位址的 uint 值。它可以表示一個變數或函數的位置。Uintptr 和 UnsafePointer 兩者間的不同在於:Uintptr 會在 Go 運行時進行類型校正,而 UnsafePointer 不會。UnsafePointer 可以被用於 Go 中任意類型向 Go 中其他任何擁有相同記憶體結構的類型轉換。如果這是你想要探索的,請在下面評論,我會寫更多關於它的東西。Uintptr 和 UnsafePointer 可以分別通過 Addr() 和 UnsafeAddr() 方法,從 reflect.Value 的對象中提取出來。這是一個展示 Uintptr 提取的例子:```go// Extract Uintptrfunc extractUintptr(v reflect.Value) (uintptr, error) {// 譯註:原文是 reflect.Kind() != reflect.Uintptr,這次錯誤的。if v.Kind() != reflect.Uintptr {return uintptr(0), errors.New("Invalid input")}var ptrVal uintptrptrVal = v.Addr()return ptrVal, nil}```這是如何提取 UnsafePointer 類型:```go// Extract UnsafePointerfunc extractUnsafePointer(v reflect.Value) (unsafe.Pointer, error) {// 譯註:原文是 reflect.Kind() != reflect.UnsafePointer,這次錯誤的。if v.Kind() != reflect.UnsafePointer {return unsafe.Pointer(0), errors.New("Invalid input")}var unsafeVal unsafe.PointerunsafeVal = unsafe.Pointer(v.UnsafeAddr())return unsafeVal, nil}```值得注意的是:上面 v.UnsafeAddr() 會返回 uintptr 值。它應該在同一行進行類型轉換,否則這個 unsafe.Pointer 的值不一定指向預期的位置。## 接下來是什麼請注意:reflect.Value 結構的所有方法在使用時都需要檢驗它們的 kind,否則很容易引發 panic。在下一篇部落格中,我會寫更多像 struct、pointer、chan、map、slice、array 等複雜類型對象的建立。敬請期待!

via: https://medium.com/kokster/go-reflection-creating-objects-from-types-part-i-primitive-types-6119e3737f5d

作者:Sidhartha Mani 譯者:yiyulantian 校對:polaris1119

本文由 GCTT 原創編譯,Go語言中文網 榮譽推出

本文由 GCTT 原創翻譯,Go語言中文網 首發。也想加入譯者行列,為開源做一些自己的貢獻嗎?歡迎加入 GCTT!
翻譯工作和譯文發表僅用於學習和交流目的,翻譯工作遵照 CC-BY-NC-SA 協議規定,如果我們的工作有侵犯到您的權益,請及時聯絡我們。
歡迎遵照 CC-BY-NC-SA 協議規定 轉載,敬請在本文中標註並保留原文/譯文連結和作者/譯者等資訊。
文章僅代表作者的知識和看法,如有不同觀點,請樓下排隊吐槽

867 次點擊  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.