GO語言學習筆記-反射篇 Study for Go ! Chapter nine - Reflect

slowlydance2me發表於2023-03-13

持續更新 Go 語言學習進度中 ......

  1. GO語言學習筆記-型別篇 Study for Go! Chapter one - Type - slowlydance2me - 部落格園 (cnblogs.com)
  2. GO語言學習筆記-表示式篇 Study for Go ! Chapter two - Expression - slowlydance2me - 部落格園 (cnblogs.com)
  3. GO語言學習筆記-函式篇 Study for Go ! Chapter three - Function - slowlydance2me - 部落格園 (cnblogs.com)

Study for Go ! Chapter nine - Reflect

1. TYPE

  • 反射讓我們能在執行初期探知物件的型別資訊和記憶體結構,這從一定程度上彌補了靜態語言在動態行為上的不足。同時,反射還是實現超程式設計的重要手段

  • 和 C 資料結構一樣,golang 物件 頭部並沒有型別指標,透過其自身是無法在執行期間獲知任何型別的相關資訊的。反射操作所需的全部資訊都源自介面變數。介面變數除儲存自身型別外,還會儲存實際物件的型別資料

  • 在面對型別時,需要區分 TYPE 和 KIND ,前者表示真是型別(靜態型別),後者表示其基礎機構(底層型別)類別

  • 除了透過實際物件獲取型別外,也可直接構造一些基礎符合型別

  • 傳入物件應區分基型別和指標型別,因為它們並不屬於同一型別

  • 方法 Elem 返回指標、陣列、切片、字典 (值)或通道的基型別

  • 只有在獲取結構體指標的基型別之後,才能遍歷它的欄位

  • 對於匿名欄位,可用多級索引 (按定義順序)直接訪問

  • FieldByName 不支援多級名稱,如有同名遮蔽,須透過匿名欄位二次獲取

  • 同樣地,輸出方法集時,一樣區分基型別和指標型別

  • 有一點和想象的不同,反射能探知當前包或外包的非匯出結構成員 (相對 reflect 而言,當前包和外包都是 “ 外包 ”)

  • 可用反射提取 struct tag,還能自動分解。其常用於 ORM 對映,或資料格式驗證

  • 輔助判斷方法 Implements、Convertible、AssignableTo 都是執行期進行動態呼叫和賦值所必須的。

 

2. Value

  • 和 TYPE 獲取型別資訊不同,Value 專注於物件例項資料讀寫

  • 介面變數會複製物件,且是 Unaddressable 的,所以想要修改目標物件,就必須要使用指標

  • 但是就算傳入指標,一樣需要透過 Elem 獲取目標物件。因為被介面儲存的指標本身是不能定址和進行設定操作的

 

Attention:

  • 不能對非匯出欄位直接進行設定操作,無論是當前包還是外包

 

  • Value.Pointer 和 Value.Int 等方法類似,將 Value.data 儲存的資料轉換為指標,目標必須是指標型別。而 UnsafeAddr 返回任何 CanAddr Value.data 地址 (相當於 & 取地址操作),比如 Elem 後的 Value,以及欄位成員地址

  • 以結構體裡的指標型別欄位為例,Pointer 返回該欄位所儲存的地址,而 UnsafeAddr 返回該欄位自身的地址 (結構物件地址 + 偏移量)

  • 可透過 Interface 方法進行型別推斷和轉換

  • 也可以直接使用 Value.Int、Bool 等方法進行型別轉換,但失敗時會引發 Panic,且不支援 ok-idom

  • 介面有兩種 nil 狀態,這是一個潛在的麻煩。解決的辦法是用 IsNil 判斷值是否為 nil

  • 也可用 unsafe 轉換後直接判斷 iface.data 是否為零值

  • 讓人無奈的是,Value 裡的某些方法 並未實現 ok-idom 或返回 error,所以得自行判斷返回的是否為 Zero Value

 

3. Method

  • 動態呼叫方法,談不上有多麻煩,只需要按 In 列表準備好 所需引數即可

  • 對於變參來說,用 CallSlice 要更方便一些

  • 無法呼叫非匯出方法,甚至無法獲取有效地址

 

4. 構建

  • 反射庫提供了內建函式 make 和 new 的對應操作,其中最有意思的就是 MakeFunc。可以用它實現通用模板,適應不同型別資料

  • golang 暫不支援泛型,所以會麻煩一點

 

5.效能

  • 反射在帶來“ 方便 ” 的同時,也造成了很大的困擾,很多人對反射避之不及,因為它會造成很大的效能損失。

  • 如果對效能要求較高,那麼須謹慎使用反射

 

相關文章