學會提升Go語言編碼效率技巧拒絕加班!
引言
在Go語言中,`slice`和`map`是我們常用的基礎類型,通過它們,我們可以輕松地處理數(shù)據(jù)。然而,你可能會注意到,為了處理這兩種數(shù)據(jù),我們不得不編寫許多實用函數(shù)。
比如,從`slice`切片中查找一個元素的位置。而這種查找又分為從前查找和從后查找。又或者,獲取`map`的所有鍵?或者所有的值?
再比如,在JavaScript中,數(shù)組的`map`、`reduce`、`filter`等函數(shù)非常好用,但是令人遺憾的是,Go標準庫沒有提供這樣的功能。
這些例子還有很多,而且都是我們在編程中經(jīng)常需要的實用函數(shù)。但是,我們的Go SDK并沒有提供這些。
那么我們應該怎么辦呢?
一種方法是自己編寫一個工具包,供項目使用,但是這個工具包的維護可能會成為一個問題,需要投入人力。
go-funk
第二種方式是使用開源庫,經(jīng)過充分的測試、驗證,并且經(jīng)常更新,以確??捎眯?。
因為我們遇到的是常見問題,所以一些人已經(jīng)做了開源庫,以供大家使用。
這樣的工具庫以Go 1.18為分界線,Go 1.18之前比較有名的是`go-funk`。
它有一個有趣的名字Repo
地址是 https://github.com/thoas/go-funk
它被官方介紹為一個現(xiàn)代化的Go實用工具庫:
"A modern Go utility library which provides helpers (map, find, contains, filter, ...)"
它提供了許多實用的函數(shù),比如`Contains`、`Difference`、`IndexOf`、`LastIndexOf`等等,具體更多的可以參考它的文檔。
然而,它有一個致命的問題,就是使用了反射。這也是無法避免的,因為在Go泛型沒有支持之前,只能通過反射來編寫滿足不同類型的函數(shù)。
舉個例子,如果不使用反射,要想支持更多的類型,就得定義很多相似名稱的函數(shù),如下所示:
func IndexOfBool(a []bool, x bool) int { } func IndexOfInt(a []int, x int) int { } func IndexOfInt32(a []int32, x int32) int { } func IndexOfInt64(a []int64, x int64) int { } func IndexOfUInt(a []uint, x uint) int { } func IndexOfUInt32(a []uint32, x uint32) int { } func IndexOfUInt64(a []uint64, x uint64) int { } func IndexOfFloat64(a []float64, x float64) int { } func IndexOfString(a []string, x string) int { }
以上函數(shù)行不行?當然行,但是會寫很多重復的代碼,并且看著也怪怪的。
在Go語言的泛型支持之前,要解決這個問題,只能通過反射。
在Go語言的泛型支持之前,處理slice和map的通用工具函數(shù)通常需要使用反射。
雖然這種方法可以幫助我們編寫更通用的代碼,但也會帶來一些性能開銷。
例如,考慮一個通用的查找函數(shù),用于在切片中查找特定的元素:
go Copy code import ( "reflect" ) func indexOf(slice interface{}, target interface{}) int { sliceValue := reflect.ValueOf(slice) for i := 0; i < sliceValue.Len(); i++ { element := sliceValue.Index(i).Interface() if element == target { return i } } return -1 }
上述函數(shù)使用了反射,它能夠接受任意類型的切片,并在其中查找目標元素。然而,這種靈活性是以性能為代價的,因為反射的開銷相對較高。
在Go 1.18引入泛型之前,我們不得不在不同類型的切片和映射上編寫類似的通用函數(shù),這可能會導致很多重復的代碼。在實際應用中,我們需要權衡代碼的通用性和性能開銷。
值得注意的是,Go語言的泛型支持已經(jīng)提供了更為優(yōu)雅和高效的解決方案,可以在不使用反射的情況下實現(xiàn)通用性。
使用泛型編寫更直觀且類型安全的通用函數(shù)
在Go 1.18及以后的版本中,你可以使用泛型編寫更直觀且類型安全的通用函數(shù)。
// IndexOf gets the index at which the first occurrence // of value is found in array or return -1 // if the value cannot be found func IndexOf(in interface{}, elem interface{}) int { inValue := reflect.ValueOf(in) elemValue := reflect.ValueOf(elem) inType := inValue.Type() if inType.Kind() == reflect.String { return strings.Index(inValue.String(), elemValue.String()) } if inType.Kind() == reflect.Slice { equalTo := equal(elem) for i := 0; i < inValue.Len(); i++ { if equalTo(reflect.Value{}, inValue.Index(i)) { return i } } } return -1 }
泛型代碼復雜,并且效率低。。。
那么Go 1.18之后已經(jīng)支持了泛型,能不能用泛型來重寫呢?
答案是:當然可以,并且已經(jīng)有人這么做了。這個庫就是 https://github.com/samber/lo
IndexOf函數(shù)實現(xiàn)
它是基于Go泛型實現(xiàn),沒有用到反射,效率高,代碼簡潔。比如剛剛的IndexOf函數(shù),在該庫中是這么實現(xiàn)的:
// IndexOf returns the index at which the first occurrence of // a value is found in an array or return -1 // if the value cannot be found. func IndexOf[T comparable](collection []T, element T) int { for i, item := range collection { if item == element { return i } } return -1 }
只需要 T 被約束為comparable 的,就可以使用==符號進行比較了,整體代碼非常簡單,并且沒有反射。
IndexOf只是lo幾十個函數(shù)中的一個,這些函數(shù)基本上覆蓋了slice、map、string等方方面面,涉及查找、比較大小、生成、map、reduce、過濾、填充、反轉、分組等等,使用方法和示例,可以參考go doc文檔。
以上就是學會提升Go語言編碼效率技巧拒絕加班!的詳細內容,更多關于Go語言編碼效率提升的資料請關注腳本之家其它相關文章!
相關文章
VSCode Golang dlv調試數(shù)據(jù)截斷問題及處理方法
這篇文章主要介紹了VSCode Golang dlv調試數(shù)據(jù)截斷問題,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-06-06Go?Gin框架優(yōu)雅重啟和停止實現(xiàn)方法示例
Web應用程序中,有時需要重啟或停止服務器,無論是因為更新代碼還是進行例行維護,這時需要保證應用程序的可用性和數(shù)據(jù)的一致性,就需要優(yōu)雅地關閉和重啟應用程序,即不丟失正在處理的請求和不拒絕新的請求,本文將詳解如何在Go語言中使用Gin這個框架實現(xiàn)優(yōu)雅的重啟停止2024-01-01Golang 函數(shù)執(zhí)行時間統(tǒng)計裝飾器的一個實現(xiàn)詳解
這篇文章主要介紹了Golang 函數(shù)執(zhí)行時間統(tǒng)計裝飾器的一個實現(xiàn)詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-03-03Go語言題解LeetCode1260二維網(wǎng)格遷移示例詳解
這篇文章主要為大家介紹了Go語言題解LeetCode1260二維網(wǎng)格遷移示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-01-01