Go 實驗報告:函數式編程之泛型

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。在 2017 年的年中,我在 GopherCon 上發表了《Go 的函數式編程》的演講。我提出了一些函數式編程的概念,Gophers 使用它,可以提高編程效率,代碼更加簡潔。![](https://raw.githubusercontent.com/studygolang/gctt-images/master/go-experience-report-generics-for-functional-patterns/functional-programming-in-go.jpeg)> 函數式編程在 Go 是可以實現,只是不明顯演講中一半是理論,另一半是可以讓人使用的模式概念,其中大約四分之一是我認為是有實踐價值的,其他的姑且值得一提。你需要"代碼產生"(code generation)以實現它們。我在 [Github repo](https://github.com/go-functional/core) 分享了這些模式,歡迎 folk 到你們的倉庫。這篇文章是關於泛型如何使 Go 函數式編程模式更加強大,且不依賴於代碼產生。這裡我沒有遵守 [如何寫實驗報告](https://github.com/golang/go/wiki/ExperienceReports) 的指導原則,我想可以用稍微不同的方式來更好地表達想法。## 一個例子讓我們從理想的 API 開始認識並探究,映射序列(Mapping over sequences)普遍存在絕大多數語言中,於是以此為例。在 Go 中,我想這個理想的 API 是這樣的:```goints := []int{1, 2, 3, 4}incremented := ints.Map(func(i int) int { return i + 1 })// incremented = []int{2, 3, 4, 5}```如你所想,`Map` 方法取代了 `for` 迴圈,它協助你寫出簡潔的代碼(pure code),使用更加便利,更重要的是你無需自己寫邊界條件(range)。上面的代碼看上去很理想,但我們必須做出不少重大改變(例如,像自動類型轉換)才能在 Go 語言中實現這個。並且,儘管上述很理想,但事實上我們不得不添加另一個特例以使特定類型的 `slices` 可以執行新的 `Map` 方法,這與我的理想背道而馳。正如Russ Cox在 [GopherCon 2017主題演講](https://www.youtube.com/watch?v=0Zbh_vmAKvk) 中所提到的,我寧願將注意力放在與泛型有關的體驗報告上。這就是這篇文章的內容。## 一個現實點的例子我認為需要對上面的 API 做一些調整。讓它在原有語言中更加實用,並且更容易地集中注意力在泛型上(而不是更多的函數式編程模式,這可以在另一篇文章中)。在這裡我們將 `[]int` 封裝了一個容器類型(container type),然後給這個容器定義一個 `Map` 方法。```goincremented := WrapSlice(ints).Map(func(i int) int { return i + 1})```這個新的容器在Go中部分實現了類型語義。在今天的Go中,除了 `[]int` 之外,沒有辦法讓單個 Wrap 函數在任何其他類型上工作,因為我們沒有泛型程式設計機制。你可以得到最接近的方法是手寫或者產生代碼,使得 Wrap 可以適用於你想要的所有類型。## 為什麼這傢伙反對代碼產生代碼產生的想法、背後的動機與技術都很好。我在之前的實驗報告中,已經寫過關於它的想法,我並不想在這裡或者其他文章中抨擊它。儘管聽起來如此,但是因為我堅信代碼產生是一個工具,需要為它選擇正確的用武之地。然而,在這裡,代碼產生絕對用錯地方了。它有一個大問題,舉個例子。假設您想要產生處理 `[] ints`,`[]string` 和自訂類型(MyCustomType)的代碼。在今天的Go中,語言引擎將無法為您的所有類型提供相同的Wrap功能。與之相反,產生器可以產生這個API的代碼:```gomyStrings := []string{...}WrapStringSlice(myStrings).Map(func(s string) string { return "hello " + s})myInts := []int{...}WrapIntSlice(myInts).Map(func(i int) int { return i + 1})myCustomTypes := []MyCustomType{...}WrapMyCustomTypeSlice(myCustomTypes).Map(func(m MyCustomType) MyCustomType { return m})```所以我們每種類型都有一個 Wrap 函數。我們為所有類型提供相容性,但是我們仍然沒有API來針對我們所有類型編寫泛型代碼。## 下一步很明顯,我正在寫關於在 Go 中添加泛型的知識,但“泛型”可能意味著很多東西。我在這裡舉例說明了我想要一個泛型 API,它有點類似函數式編程模式。您可以將此 API 外推到其他函數式編程模式。首先,我希望能夠在 `[]T` 或者 `map[T]U` (T和U是任意類型)上調用 Map,並且能夠將這些值轉換為其他 slices 或 maps ([]A and map[B]C)。和我上一篇文章一樣,我不打算在Go中發明泛型的文法,我只是想展示我想要的樣子。我可以寫一篇後續文章來提出一種文法。## WrapSlice我展示了我想要 WrapSlice 和 Map 看起來像上面那樣,但這是一個簡單的例子。Map 的強大功能是可以將切片從一種類型轉換為另一種(即T1 => T2)。除了傳遞給Map的函數簽名(注意參數和傳回值是不同的類型)之外,該函數看起來與上例相同:```goints := []int{1, 2, 3, 4}strs := WrapSlice(ints).Map(func(i int) string { return strconv.Itoa(i*2)})// var strs []string = []string{"2", "4", "6", "8"}bites := WrapSlice(strs).Map(func(s string) []byte { return []byte(s)})// var bites [][]byte = []byte{// []byte{50},// []byte{52},// []byte{54},// []byte{56},// }```這裡我們已經將 `[]int` 轉換為 `[]string`,然後將 `[]string`轉換為 `[]byte`## WrapMapWrapMap 在邏輯上與 WrapSlice 相似,只不過這次我們正在轉換索引值對。例如,這就是 map[string]int 轉換到 map[int]string :```gom := map[string]int{ "1": 1, "2": 2, "3": 3,}converted := WrapMap(m).Map(func(k string, v int) (int, string) { newKey := strconv.Itoa(v) newVal, _ := strconv.Atoi(k) return newKey, newVal})// var converted map[int]string = { 1: "1", 2: "2", 3: "3" }```## 結論從 `Wrap*` / `Map` 樣本中,重要內容是它們適用於所有 `T` 和 `U` 類型。它們可以在語言代碼之外編寫,而可以進入標準庫,第三方“FP”包,甚至是它們的生態系統。最後,如果你看不到上述例子中泛型的用法,我會在這裡解釋。`WrapList` 通過列表元素的類型(即 []T 中的 T )來參數化,並且 `WrapMap` 通過鍵的類型和值的類型(即, `map[T]U` )被參數化。然後,在通過映射表(即 `Map[U]` )和 Map 由新的索引值類型進行參數化的情況下,通過新的清單類型對 Map 進行參數化(在映射到 Map 的情況下)(即 `Map[X,Y]` )。就像我之前說過的,我沒有在這裡正式指定任何文法,但我確實使用了 bracket 文法(我更喜歡)來說明型別參數。沒有任何承諾 —— 泛型文法規範是一個很大的話題!——— 我打算寫一個更詳細的文法提案。直到那時…繼續搖滾吧,Gophers!

via: https://medium.com/go-in-5-minutes/go-experience-report-generics-for-functional-patterns-eb6ce737bc1

作者:Aaron Schlesinger 譯者:lightfish-zhang 校對:polaris1119

本文由 GCTT 原創編譯,Go語言中文網 榮譽推出

本文由 GCTT 原創翻譯,Go語言中文網 首發。也想加入譯者行列,為開源做一些自己的貢獻嗎?歡迎加入 GCTT!
翻譯工作和譯文發表僅用於學習和交流目的,翻譯工作遵照 CC-BY-NC-SA 協議規定,如果我們的工作有侵犯到您的權益,請及時聯絡我們。
歡迎遵照 CC-BY-NC-SA 協議規定 轉載,敬請在本文中標註並保留原文/譯文連結和作者/譯者等資訊。
文章僅代表作者的知識和看法,如有不同觀點,請樓下排隊吐槽

598 次點擊  
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.