Golang的流式程式碼 - 0x46
Go 1.18 剛剛釋出,這意味著 Go 現在正式支援泛型。出於好奇,我決定研究建立一個實現類似於 Java 流的庫。我的簡單實現的目標是支援使用兩個操作處理切片的元素:對映和過濾。
如果您只想檢視程式碼,則可以在此處找到儲存庫。
我沒有在本文中展示實現,坦率地說,它並不那麼有趣。
我們將只看使用這個庫產生的程式碼。這樣我們就可以評估使用類似的庫是否會使 Go 程式更具可讀性。
過濾
在本節中,我們將嘗試過濾一個整數切片,在結果切片中只留下偶數。首先讓我們看一下使用帶有for迴圈的標準方法執行此操作的一段程式碼:
func OnlyEven(slice []int) []int { var result []int for _, element := range slice { if element%2 == 0 { result = append(result, element) } } return result } |
我相信大多數人在使用 Go 程式設計時編寫了數百個類似的函式。這樣簡單的函式編寫起來非常重複,但很容易識別,並且通常與我剛剛介紹的函式一樣簡單。
現在讓我們看看使用我編寫的庫實現的相同功能:
func OnlyEven(slice []int) []int { return streams.New(slice). Filter(onlyEven). Collect() } func onlyEven(v int) bool { return v%2 == 0 } |
為了便於閱讀,我用命名函式替換了匿名函式。我相信這段程式碼相對容易閱讀,但我很難判斷它是否比之前的函式更具可讀性。然而,它似乎寫起來更快,並且包含的樣板較少,這可能會損害可讀性。
總的來說,我相信for在某些情況下,過濾器呼叫鏈可能比迴圈內的許多語句更具可讀性。話雖如此,我認為普通for迴圈不會令人討厭或難以閱讀,因此很難判斷這是否解決了任何實際問題。
過濾和對映
現在讓我們試著讓這個例子更復雜一些。首先我們將過濾這些值,然後將它們從 對映int到string,然後過濾掉超過一位數的值。為了簡單len起見,我們將只使用類似RuneCountInString.
同樣,首先讓我們嘗試一個傳統的for迴圈:
func OnlyEvenAsStrings(slice []int) []string { var result []int for _, element := range slice { if element%2 != 0 { continue } s := strconv.Itoa(element) if len(s) > 1 { continue } result = append(result, s) } return result |
如您所見,我試圖以一種避免巢狀條件語句的方式構造程式碼。儘管可以透過多種方式編寫此函式,但我認為這種方法使控制流更易於遵循。所有條件語句都可以清楚地識別為過濾元素的條件。
現在讓我們嘗試對我的庫做同樣的事情:
func OnlyEvenAsStrings(slice []int) []string { return streams.Map( streams.New(slice).Filter(onlyEven), strconv.Itoa, ). Filter(onlyOneByte). Collect() } func onlyEven(v int) bool { return v%2 == 0 } func onlyOneByte(v string) bool { return len(v) == 1 } |
不幸的是,正如您所看到的,程式碼突然變得不那麼可讀了。在我看來,函式應該是這樣的:
func OnlyEvenAsStrings(slice []int) []string { return streams.New(slice). Filter(onlyEven). Map(strconv.Itoa). Filter(onlyOneByte). Collect() } |
不幸的是,以Go中泛型的工作方式,目前這是不可能的。
真實的例子看起來很糟糕,因為方法不能用額外的型別引數進行引數化。
由於這個原因,我不得不使用一個頂層函式。這是很不幸的,因為我認為我的理想化例子會更有意義。
目前產生的程式碼在可讀性方面肯定是完全失敗的。
關於效能的簡短說明
出於好奇,我對第一節中的過濾函式進行了基準測試。一個簡單的迴圈的效能比試圖用我的庫來執行同樣的任務要好。雖然我的實現可能過於天真,但我不認為這與我的程式碼有必然聯絡。我假設這是由編譯器在使用簡單迴圈時進行的各種最佳化造成的。因此,一個更復雜的實現很可能總是失敗。
相關文章
- Golang 流式解析 JsonGolangJSON
- 直播網站程式原始碼,FlowLayoutManager 流式佈局網站原始碼
- golang程式碼生成工具Golang
- 搭建sonarqube分析golang程式碼Golang
- golang http/transport 程式碼分析GolangHTTP
- Golang中常用的程式碼優化點Golang優化
- gout 新版本釋出,golang實現的http 流式客戶端GolangHTTP客戶端
- Golang框架實戰-KisFlow流式計算框架(4)-資料流Golang框架
- golang 中,對稱加密的程式碼實現Golang加密
- Golang中的interface程式碼和允許效果Golang
- 讓程式碼變得優雅簡潔的神器:Java8 Stream流式程式設計Java程式設計
- Golang 扁平專案程式碼結構Golang
- golang如何優雅的編寫事務程式碼Golang
- golangci-lint 程式碼檢查GolangGC
- golang echo 程式碼詳解之模版篇Golang
- golang echo 程式碼詳解之 log 篇Golang
- 從別人的程式碼中學習golang系列--03Golang
- 從別人的程式碼中學習golang系列--01Golang
- 從別人的程式碼中學習golang系列--02Golang
- 那些我的程式碼中從不用的 Golang 特性 – 馬特-萊亞Golang
- 萬字詳解 | Java 流式程式設計Java程式設計
- 流式介面
- 玩轉Golang的channel,二百行程式碼實現PubSub模式Golang行程模式
- 【GoLang 那點事】gRPC 之流式呼叫原理 http2 協議分析(四)GolangRPCHTTP協議
- 深入探索Spring AI:原始碼分析流式回答SpringAI原始碼
- 基於 goc 的 Golang 程式碼 VsCode 實時染色方案GolangVSCode
- Java8 新特性 —— Stream 流式程式設計Java程式設計
- Java8 的流式操作Java
- golang映象指令碼Golang指令碼
- golang中的socket程式設計Golang程式設計
- Golang, 以 9 個簡短程式碼片段,弄懂 defer 的使用特點Golang
- 三段程式碼打造好看的流式佈局,flutter之wrap【flutter20個例項之七】Flutter
- golang程式版本管理Golang
- ReactiveX流式程式設計—從xstream講起React程式設計
- bilibili 彈幕協議分析,golang程式碼還原協議Golang
- 河蟹安裝golang.org部分支援庫程式碼Golang
- Angular 中的響應式程式設計 -- 淺淡 Rx 的流式思維Angular程式設計
- 【譯】如何使用 Golang 中的 Go-Routines 寫出高效能的程式碼Golang