<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Go 還是需要泛型的

          共 5721字,需瀏覽 12分鐘

           ·

          2021-03-01 13:59

          Go 語言之父早期提到過 less is more[1] 的哲學(xué),可惜社區(qū)里有不少人被帶偏了。

          每次 Go 增加語法上的新特性、新功能,就會有原教旨主義者跳出來扔出一句 less is more(或者也可能是大道至簡),揚(yáng)長而去,留下風(fēng)中凌亂的你。

          即使到了官方已經(jīng)確定要增加泛型功能的 2020 年,依然有人煞有介事地寫文章說為什么 go doesn't need generics[2],作為理智的 Gopher,最好不要對別人的結(jié)論盡信,至少要看看其它語言社區(qū)怎么看待這件事情。

          Java 社區(qū)是怎么理解泛型的必要性的呢?

          簡而言之,泛型使類型(類和接口)能夠在定義類、接口和方法時成為參數(shù)。就像我們更熟悉的在方法聲明中使用的形式參數(shù)一樣,類型參數(shù)為你提供了一種用不同的輸入重復(fù)使用相同代碼的方法。不同的是,形式參數(shù)的輸入是值,而類型參數(shù)的輸入是類型。

          與非泛型代碼相比,使用泛型的代碼有很多好處。

          • 在編譯時進(jìn)行強(qiáng)類型檢查。Java 編譯器對泛型代碼進(jìn)行強(qiáng)類型檢查,如果代碼違反類型安全就會報錯。編譯時的錯誤比運(yùn)行時的錯誤更易修復(fù)。

          • 消除類型轉(zhuǎn)換。下面這段代碼片段在沒有泛型時,需要類型轉(zhuǎn)換:

          List list = new ArrayList();
          list.add("hello");
          String s = (String) list.get(0);

          用泛型重寫,代碼不再需要進(jìn)行類型轉(zhuǎn)換:

          List<String> list = new ArrayList<String>();
          list.add("hello");
          String s = list.get(0);   // no cast
          • 程序員可以編寫泛型算法 使用泛型可以實(shí)現(xiàn)在不同類型上都可以工作的泛型算法的同時,保證類型安全性。

          Gopher 可能對“類型安全”不太熟悉,舉個例子,我們可以用 gods 庫來實(shí)現(xiàn)下面的數(shù)據(jù)結(jié)構(gòu)。

          package main

          import (
           "fmt"

           sll "github.com/emirpasic/gods/lists/singlylinkedlist"
          )

          func main() {
           list := sll.New()
           list.Add("a")                     // ["a"]
          }

          我們的本意是實(shí)現(xiàn)一個 string 的單鏈表,但是通用的數(shù)據(jù)結(jié)構(gòu)庫沒有辦法阻止用戶向該 list 內(nèi)插入非 string 類型的值,比如用戶可以這樣:

           list := sll.New()
           list.Add("a")                     // ["a"]
           list.Add(2)                       // ["a", 2]

          這顯然不是我們想要的結(jié)果。

          可見泛型最常見的場景是在類型安全的前提下實(shí)現(xiàn)算法流程,對于 Go 來說,我們使用的數(shù)據(jù)結(jié)構(gòu)和算法來源有兩個地方:container 標(biāo)準(zhǔn)庫、第三方數(shù)據(jù)結(jié)構(gòu)庫,如 gods[3] 。

          和我們前面舉的例子一樣,標(biāo)準(zhǔn)庫的通用 container 的大多接口也是接收空 interface{},或返回空 interface{}:

          package main

          import (
           "container/list"
          )

          func main() {
           l := list.New()
           l.PushBack(4)
           l.PushFront("bad value")
          }

          做不到類型安全的話,那么用戶代碼就可能在運(yùn)行期間發(fā)生斷言產(chǎn)生的 panic/error。除了容器的功能容易被破壞,類似下面的 bug 也挺容易出現(xiàn)的:

          package main

          import "fmt"

          type mystring string

          func main() {
           var a interface{} = "abc"
           var b interface{} = mystring("abc")
           fmt.Println(a == b)
          }

          社區(qū)的其它嘗試

          社區(qū)曾經(jīng)有一些靠代碼生成實(shí)現(xiàn)的泛型庫,如genny[4],其本質(zhì)是使用文本替換來實(shí)現(xiàn)多種類型的代碼生成。

          genny 使用也比較簡單,比如 example 里的例子:

          package queue

          import "github.com/cheekybits/genny/generic"

          // NOTE: this is how easy it is to define a generic type
          type Something generic.Type

          // SomethingQueue is a queue of Somethings.
          type SomethingQueue struct {
            items []Something
          }

          func NewSomethingQueue() *SomethingQueue {
            return &SomethingQueue{items: make([]Something, 0)}
          }
          func (q *SomethingQueue) Push(item Something) {
            q.items = append(q.items, item)
          }
          func (q *SomethingQueue) Pop() Something {
            item := q.items[0]
            q.items = q.items[1:]
            return item
          }

          cat source.go | genny gen "Something=string"

          // This file was automatically generated by genny.
          // Any changes will be lost if this file is regenerated.
          // see https://github.com/cheekybits/genny

          package queue

          // StringQueue is a queue of Strings.
          type StringQueue struct {
            items []string
          }

          func NewStringQueue() *StringQueue {
            return &StringQueue{items: make([]string0)}
          }
          func (q *StringQueue) Push(item string) {
            q.items = append(q.items, item)
          }
          func (q *StringQueue) Pop() string {
            item := q.items[0]
            q.items = q.items[1:]
            return item
          }

          想實(shí)現(xiàn)多種類型的結(jié)構(gòu)就在生成代碼時傳入多種類型就可以了。

          這種做法和人們調(diào)侃 Go 泛型時使用的 gif[5] 本質(zhì)上也沒什么區(qū)別。

          語言的原生支持能讓我們省事,并且也能在實(shí)現(xiàn)上更加嚴(yán)謹(jǐn)。

          在 《Rise and Fall of Software Recipes》一書中,有這么一個故事:

          Among the recent projects failing because (or despite) of strong processes, Obamacare is a telling example. It involves 50 contractors, has cost fortunes, was delivered late and crippled with bugs. It was developed using a typical waterfall process, and if only because of that, the Agile community started howling, claiming that they would have made the project a success[Healthcare.gov failure].

          And when an Agile project fails like Universal Credit in Great-Britain[UniversalCredit] [NAO2013], even when the full report states that the lack of detailed blueprint – typical of Agile methodologies – was one of the factors that caused the failure, common Agile wisdom says it is because it was not applied properly, or should I say, not Agile enough.

          簡而言之,就是敏捷大師們其實(shí)非常雙標(biāo),他們給出的方法論也不一定靠譜,反正成功了就是大師方法得當(dāng),失敗了就是我們執(zhí)行不力沒有學(xué)到精髓。正著說反著說都有道理。

          再看看現(xiàn)在的 Go 社區(qū),buzzwords 也很多,如果一個特性大師不想做,那就是 less is more。如果一個特性大師想做,那就是 orthogonal,非常客觀。

          對于不想迷信大師的 Gopher 來說,多聽聽批評意見沒壞處:go is not good[6]。

          [1]

          less is more: https://en.wikipedia.org/wiki/Less_is_more

          [2]

          go doesn't need generics: https://dzone.com/articles/go-doesnt-need-generics

          [3]

          gods: https://github.com/emirpasic/gods

          [4]

          genny: https://github.com/cheekybits/genny

          [5]

          gif: https://twitter.com/yogthos/status/883058510275149826

          [6]

          go is not good: https://github.com/ksimka/go-is-not-good


          瀏覽 76
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  可以看的亚洲黄片视频 | 红桃视频亚洲 | 青青操成人 | 99一二区| 网络红人思瑞视频在线观看 |