[Golang]: 進階用法
#golang #annotation #reflection #interface型別轉換 #tag
主要介紹在 Golang 中相對進階的用法,如interface、reflection、Tag。善用這些技巧可以使得程式碼更加簡潔。ex, 透過 interface 的技巧使得 func 的參數更加有彈性;使用 reflection 進一步資料屬於的型態、甚至達到無須知道 type 也能夠修改資料; Tag 讓你 mapping 資料更加方便。
Golang Interface
Interface{} 型別轉換
Interface{} 型別轉換
在Golang 中Interface
資料結構是相當重要的,由於 Golang 屬於強型別語言,因此在func 中的 parameter 與 return value 時常會因為結構受限造成許多的不方便,然而interface
就是來解決問題。(它本身可以是Golang 語言中任一 type
進而解決該問題。) @in play ground
如上述程式碼,實作ToString 方法時,需要傳入各種型態(type)的參數,此時Interface 的彈性就派上用場了,藉由還原的語法進行實作,繞過強型別參數型態固定的問題。
Interface{} 多形
Interface{} 多形
此外在Golang中若要做到 abstract method 的話則也需要 interface
,它提供抽象方法的功能,並且可以在compile time 就能排除抽象方法實作上部份錯誤,ex. 少定義方法等...。換句話說,在Golang中實作多型
須仰賴interface
。@in play ground
Golang Reflection
Reflection
是一種用於描述程式語言的工具。由於在Golang 中任何型別都可以是一種Interface
,因此時常需要與Reflection
進行搭配,故筆者認為是一種Interface
的配套工具。主要有三種用法:
映射出Interface 的資料型別 @playground
映射出Interface 的值 @playground
將某interface 資料注入到其他interface 中。 @palyground
主要透過Call by Reference 的原理進行修改,因此dest 型態必須為
Ptr
。搭配
reflect.ValueOf.Elem.Field
找出struct filed 的位置進而修改資料。
Golang Tag
在Golang Struct 資料結構中,可自定義 Tag,有點類似於其他語言的Annotation,例如在判讀 Json 的Key 值時,須利用`json:"
name"`
的方式填入。然而在學習Golang 的初期時常會勿以為 Tag 是不可定義的,因為並不清楚如何取用。然而Reflection 工具此時就得到了一大作用,由於是描述程式語言的工具,因此可透過該工具將Tag 取出。@playground
Golang 低階指標用法 ( uintptr, unsafe.Pointer)
在Golang 語言中除了正規的正常的寫法之外,也提供低階的程式設計模式,如可直接調用Unix 系統的C程式的cgo。但這種方式是不被建議使用的,因為直接調用很容易出現非預期的錯誤,除非特殊需要。若要Golang 中使用這一類低階的程式設計,則需宣告import "unsafe"
字樣,語意上表示從外部匯入unsafe 套件,但實際上是由編譯器直接調用隱藏功能。ex: net, syscall, os, runtime 等大多程式設計不太需要用到的。
uintptr 屬於Golang 基礎型態的一種,事實上是 Integer 型別,且可以接各種型態的指標。
unsafe.Pointer 是將任何型別的東西轉換成
*ArbitraryType
而 ArbitraryType 的定義為type ArbitraryType int
,因此實際上也是一種 Integer 型別。
Escape Analysis 演算法
指的是在編譯器端,對於程式碼編譯後,針對指標 (Pointer) 資料結構進行優化,並計算出需要多少的Heap 儲存。往往在Golang 中,時常使用到指標類型的結構,然而只要有該函式之外的呼叫,編譯器則會預先預先多配發空間,進而觸發GC(Grabage Collection)機制。
例如以下圖式為例: 單純透過指標的方式印出整數陣列,正規寫法如Listing 1 直接使用外部func 印出,優化做法透過 unsafe 的方式呼叫外部func。
在Golang中使用unsafe 直接調用Compile 的Pointer編譯器則不會預先產出Heap,也因此能避免該問題,但壞處是可能會遇到預期之外的錯誤(警語)。如上圖程式碼,都只是印出數字,但透過 unsafe pointer 調用的,使用的記憶體大小是預設的50倍,Heap 的大小是 3倍(下圖所示)。
Reference
[1] Wang, Cong, et al. "Escape from escape analysis of Golang." Proceedings of the ACM/IEEE 42nd International Conference on Software Engineering: Software Engineering in Practice. 2020.
Last updated