<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』Go 1.18 泛型的一些技巧和困擾

          共 3506字,需瀏覽 8分鐘

           ·

          2021-11-19 09:12

          截至2021年11月17日,社區(qū)可能還沒(méi)有使用 Go 1.18 泛型功能的緩存庫(kù)。

          我嘗試在這里實(shí)現(xiàn)了第一個(gè) Go 1.18 泛型的緩存庫(kù)。如果你能夠給的 GitHub 加個(gè) Star,我會(huì)感到非常高興。https://github.com/Code-Hex/go-generics-cache

          在這篇文章中,我將介紹我在開(kāi)發(fā)這個(gè)緩存庫(kù)時(shí)遇到的關(guān)于 Go 泛型的一些情況,以及我發(fā)現(xiàn)的一些技巧和困擾。


          對(duì)任何類(lèi)型都返回零值

          你經(jīng)常會(huì)寫(xiě)一些返回 anyerror的代碼,比如說(shuō)下面這樣。當(dāng)一個(gè)函數(shù)發(fā)生錯(cuò)誤時(shí),你會(huì)寫(xiě)一些返回零值和錯(cuò)誤的代碼,但現(xiàn)在你需要換一種思維方式。

          func?Do[V?any](v?V)?(V,?error)?{
          ????if?err?:=?validate(v);?err?!=?nil?{
          ????????//?What?should?we?return?here?
          ????}
          ????return?v,?nil
          }

          func?validate[V?any](v?V)?error

          假設(shè)你在這里寫(xiě)return 0, err。這將是一個(gè)編譯錯(cuò)誤。原因是any類(lèi)型可以是int類(lèi)型以外的類(lèi)型,比如string類(lèi)型。那么我們應(yīng)該怎么做呢?

          讓我們用類(lèi)型參數(shù)的V聲明一次變量。然后你可以把它寫(xiě)成可編譯的形式,如下:

          func?Do[V?any](v?V)?(V,?error)?{
          ????var?ret?V
          ????if?err?:=?validate(v);?err?!=?nil?{
          ????????return?ret,?err
          ????}
          ????return?v,?nil
          }

          此外,可以使用帶命名的返回值來(lái)簡(jiǎn)化單行的書(shū)寫(xiě)。

          func?Do[V?any](v?V)?(ret?V,?_?error)?{
          ????if?err?:=?validate(v);?err?!=?nil?{
          ????????return?ret,?err
          ????}
          ????return?v,?nil
          }

          https://gotipplay.golang.org/p/0UqA0PIO9X8


          不要試圖用約束做類(lèi)型轉(zhuǎn)換


          我想提供兩個(gè)方法,IncrementDecrement。它們可以從go-generics-cache(https://github.com/Code-Hex/go-generics-cache)庫(kù)中增加或減少值,如果存儲(chǔ)的值滿(mǎn)足Number約束(https://github.com/Code-Hex/go-generics-cache/blob/d5c3dda0e57b4c533c1e744869032c33a4fc2d9e/constraint.go#L5-L8)。

          讓我們用Increment方法作為一個(gè)例子。我最初寫(xiě)的代碼是這樣的:

          type?Cache[K?comparable,?V?any]?struct?{
          ????items?map[K]V
          }

          func?(c?*Cache[K,?V])?Increment(k?K,?n?V)?(val?V,?_?error)?{
          ????got,?ok?:=?c.items[k]
          ????if?!ok?{
          ????????return?val,?errors.New("not?found")
          ????}

          ????switch?(interface{})(n).(type)?{
          ????case?Number:
          ????????nv?:=?got?+?n
          ????????c.items[k]?=?nv
          ????????return?nv,?nil
          ????}
          ????return?val,?nil
          }

          我在考慮使用值n V的類(lèi)型來(lái)匹配被滿(mǎn)足的約束。如果滿(mǎn)足Number約束,這個(gè)方法就會(huì)增加,否則什么都不做。

          這將不會(huì)被編譯。

          1. Go 不為約束條件提供條件分支
          2. 約束是一個(gè)接口,Go 不允許使用接口進(jìn)行類(lèi)型斷言
          3. n的類(lèi)型沒(méi)有確定,所以+操作是不可能的
          4. 首先,不能保證items的類(lèi)型與n的類(lèi)型相同

          為了解決這些問(wèn)題,我決定嵌入Cache結(jié)構(gòu)。我還定義了一個(gè)NumberCache結(jié)構(gòu),可以一直處理Number約束。

          • 繼承 Cache結(jié)構(gòu)體所持有的字段數(shù)據(jù)
          • 處理 Cache的方法
          type?NumberCache[K?comparable,?V?Number]?struct?{
          ????*Cache[K,?V]
          }

          這樣,我們可以保證傳遞給Cache結(jié)構(gòu)的值的類(lèi)型永遠(yuǎn)是Number的約束。所以我們可以給NumberCache結(jié)構(gòu)添加一個(gè)Increment方法。

          func?(c?*NumberCache[K,?V])?Increment(k?K,?n?V)?(val?V,?_?error)?{
          ????got,?ok?:=?c.Cache.items[k]
          ????if?!ok?{
          ????????return?val,?errors.New("not?found")
          ????}
          ????nv?:=?got?+?n
          ????c.Cache.items[k]?=?nv
          ????return?val,?nil
          }

          https://gotipplay.golang.org/p/poQeWw4UE_L


          使我困擾的點(diǎn)


          讓我們?cè)倏匆幌?code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">Cache結(jié)構(gòu)的定義。

          type?Cache[K?comparable,?V?any]?struct?{
          ????items?map[K]V
          }

          Go 范型被定義為一種帶有約束的語(yǔ)言規(guī)范,這種約束被稱(chēng)為 comparable。這允許只有類(lèi)型可以使用 ==!=。

          我覺(jué)得這個(gè)約束條件讓我很困擾。讓我解釋一下困擾我的原因。

          我定義了一個(gè)函數(shù)來(lái)比較兩個(gè) comparable 的值。

          func?Equal[T?comparable](v1,?v2?T)?bool?{
          ????return?v1?==?v2
          }

          只允許 comparable 的類(lèi)型,如果在編譯時(shí)將不可比較的類(lèi)型傳遞給函數(shù),就會(huì)導(dǎo)致錯(cuò)誤。你可能認(rèn)為這很有用。

          然而,根據(jù) Go 的規(guī)范,interface{}也滿(mǎn)足這個(gè)可比較的約束。

          如果interface{}可以被滿(mǎn)足,下面的代碼就可以被編譯了。

          func?main()?{
          ????v1?:=?interface{}(func()?{})
          ????v2?:=?interface{}(func()?{})
          ????Equal(v1,?v2)
          }

          這表明func()類(lèi)型是一個(gè)不可比較的類(lèi)型。但可以通過(guò)將其轉(zhuǎn)換為interface{}類(lèi)型來(lái)轉(zhuǎn)換為可比較的類(lèi)型。

          interface{}類(lèi)型只有在運(yùn)行時(shí)才能知道它是否是一個(gè)可比較的類(lèi)型。

          如果這是一段復(fù)雜的代碼,可能很難被注意到。

          https://gotipplay.golang.org/p/tbKKuehbzUv

          我相信我們需要另一個(gè)不接受interface{}的可比約束,以便在編譯時(shí)注意到。

          這種約束可以由 Go 用戶(hù)來(lái)定義嗎?目前的答案是不能。

          這是因?yàn)?code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">comparable約束包含 "可比較的結(jié)構(gòu)體" 和 "可比較的數(shù)組"。

          這些約束目前不能由 Go 用戶(hù)定義。因此,我想把它們作為 Go 規(guī)范來(lái)提供。

          我還為此創(chuàng)建了一個(gè)提案,如果你也認(rèn)同這個(gè)說(shuō)法,請(qǐng)?jiān)?GitHub issue 上給我??,我將不勝感激。https://github.com/golang/go/issues/49587


          文中提到的鏈接

          • comparable https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md#comparable-types-in-constraints



          原文信息

          原文地址:https://dev.to/codehex/some-tips-and-bothers-for-go-118-generics-lc7

          原文作者:Kei Kamikawa

          本文永久鏈接:https://github.com/gocn/translator/blob/master/2021/w46_some-tips-and-bothers-for-go-118-generics.md

          譯者:Cluas


          想要了解關(guān)于 Go 的更多資訊,還可以通過(guò)掃描的方式,進(jìn)群一起探討哦~



          瀏覽 57
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  91大神免费看 | 久久人人妻人人做人人玩精品 | 黄色国产无码 | 中文字幕无码在线播放 | 免费无码国产在线观看 |