去面試發現蠻多公司會問關於 Go 的 GC 跟 GMP,和其他底層的原理
花了點時間搞懂之後技術欠債清單上的大石頭又少了幾個,不過還是要繼續還債XD
Go 推出泛型已經有一段時間了
雖然在實際作業時程式碼不會看不懂,不過要寫的時候還是會卡卡的
找個時間練習一下,畢竟以前也沒用過
這篇的原文是 Go 官方的泛型教學,可以在參考連結找到
更深入的實作原理跟效能測試請參考連結
一般在撰寫程式時,如果有同樣的 function,只是實作方法不同
此時我們可以將 function 抽象化為 interface,由實際的對象來實作
泛型也是一樣的概念,只是改為將 parameter 抽象化
這樣就不需要撰寫相同實作,只是類型不同的程式碼
可以由 Go 官網教學提供的程式碼來看看實際的例子
可以發現這段程式碼就是需要泛型的原因
做的實作是差不多的,只有因為參數類型不同,就要多寫一次
func main() {
// Initialize a map for the integer values
ints := map[string]int64{
"first": 34,
"second": 12,
}
// Initialize a map for the float values
floats := map[string]float64{
"first": 35.98,
"second": 26.99,
}
fmt.Printf("Non-Generic Sums: %v and %v\n",
SumInts(ints),
SumFloats(floats))
}
// SumInts adds together the values of m.
func SumInts(m map[string]int64) int64 {
var s int64
for _, v := range m {
s += v
}
return s
}
// SumFloats adds together the values of m.
func SumFloats(m map[string]float64) float64 {
var s float64
for _, v := range m {
s += v
}
return s
}
泛型是在 Go 1.18 以後才有的功能
泛型是在 Go 1.18 以後才有的功能
泛型是在 Go 1.18 以後才有的功能
所以版本不到是用不了的
接著來加入兩段程式碼來觀察變化,來改良之前要重複寫好幾次的問題
fmt.Printf("Generic Sums: %v and %v\n",
SumIntsOrFloats[string, int64](ints),
SumIntsOrFloats[string, float64](floats))
// SumIntsOrFloats sums the values of map m. It supports both int64 and float64
// as types for map values.
func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V {
var s V
for _, v := range m {
s += v
}
return s
}
SumIntsOrFloats[string, int64](ints)
SumIntsOrFloats[string, float64](floats)
這兩行程式碼的型別宣告是多餘的,可以刪除,但是在沒有參數的情況下還是需要宣告型別。// any is an alias for interface{} and is equivalent to interface{} in all ways.
type any = interface{}
// comparable is an interface that is implemented by all comparable types
// (booleans, numbers, strings, pointers, channels, arrays of comparable types,
// structs whose fields are all comparable types).
// The comparable interface may only be used as a type parameter constraint,
// not as the type of a variable.
type comparable interface{ comparable }
對於泛型,可以使用 interface 來宣告
type Number interface {
int64 | float64
}
在原來的函式就可以改為用 interface 作為約束
// SumNumbers sums the values of map m. It supports both integers
// and floats as map values.
func SumNumbers[K comparable, V Number](m map[K]V) V {
var s V
for _, v := range m {
s += v
}
return s
}
完成後的程式碼可以在官方教學裡面找到
https://go.dev/blog/when-generics
https://zhuanlan.zhihu.com/p/509290914
https://www.dolthub.com/blog/2022-04-01-fast-generics/
https://planetscale.com/blog/generics-can-make-your-go-code-slower