<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泛型系列:Go1.18 類型約束那些事

          共 2450字,需瀏覽 5分鐘

           ·

          2021-11-17 23:15

          閱讀本文大概需要 6 分鐘。

          大家好,我是 polarisxu。

          上篇《Go泛型系列:提前掌握Go泛型的基本使用》簡單講解了泛型中的約束,但約束相關(guān)內(nèi)容遠(yuǎn)不止那些,本文介紹更多約束相關(guān)內(nèi)容。

          請安裝最新的 tip 版本,方便驗(yàn)證本文的內(nèi)容。當(dāng)然,也可以通過 https://gotipplay.golang.org/?在線驗(yàn)證。

          01 語法變更

          上次提到,定義約束的語法類似這樣:

          type?Addable?interface?{
          ?type?int,?int8,?int16,?int32,?int64,?uint,?uint8,?uint16,?uint32,?uint64,?uintptr,?float32,?float64,?complex64,?complex128,?string
          }

          不過目前已經(jīng)確認(rèn),語法改成如下形式:

          type?Addable?interface?{
          ??int?|?int8?|?int16?|?int32?|?int64?|?uint?|?uint8?|?uint16?|?uint32?|?uint64?|?uintptr?|?float32?|?float64?|?complex64?|?complex128?|?string
          }

          對于這樣的修改,大家褒貶不一。就語義來說,新的方式?|?有或之意,更貼切,而且少了一個(gè)?type,更簡潔。

          02 額外用法

          除了以上提到的優(yōu)點(diǎn),新的方式還還有額外的用途,也就是不用每次都定義一個(gè)接口約束。

          看一個(gè)具體示例:

          package?main

          import?(
          ?"fmt"
          )

          func?add[T?int|float64](a,?b?T)?T?{
          ?return?a?+?b
          }

          func?main()?{
          ?fmt.Println(add(1,?2))
          ?fmt.Println(add(1.2,?2.3))
          ??//?fmt.Println(add("a",?"b"))
          }
          //?Output:
          //?3
          //?3.5

          最后注釋的一行代碼,會編譯報(bào)錯(cuò):string does not satisfy int|float64

          注意 add 函數(shù)的泛型約束:T int|float64。如果約束是逗號分隔,無法采用這種語法:

          func?add[T?int,float64](a,?b?T)?T

          以上代碼顯然很不友好,編譯器也不好解析。

          采用了?|?后,不需要每次都定義接口約束,可以讓代碼更少。不過,這種方式建議只在少數(shù)類型約束時(shí)才適合,否則可讀性太差。

          除了以上用法,約束還有一種用法。

          在 Go 語言中,基于某類型定義新類型,有時(shí)可能希望泛型約束是某類型的所有衍生類型。看一個(gè)具體例子:

          package?main

          import?(
          ?"fmt"
          )

          func?add[T?~string](x,?y?T)?T?{
          ?return?x?+?y
          }

          type?MyString?string

          func?main()?{
          ?var?x?string?=?"ab"
          ?var?y?MyString?=?"cd"
          ?fmt.Println(add(x,?x))
          ?fmt.Println(add(y,?y))
          }

          //?Output:
          //?abab
          //?cdcd

          注意 add 函數(shù)的簽名:

          func?add[T?~string](x,?y?T)?T

          約束?~string??表示支持 string 類型以及底層是 string 類型的類型,因此 MyString 類型值也可以傳遞給 add。

          03 注意事項(xiàng)

          約束形式的多樣性,導(dǎo)致 Go 泛型語法一下子復(fù)雜起來:

          //?沒有任何約束
          func?add[T?any](x,?y?T)?T
          //?約束?Addble?(需要單獨(dú)定義)
          func?add[T?Addble](x,?y?T)?T
          //?約束允許?int?或?float64?類型
          func?add[T?int|float64](x,?y?T)?T
          //?約束允許底層類型是?string?的類型(包括?string?類型)
          func?add[T?~string](x,?y?T)?T

          在泛型中,有些場景可能想當(dāng)然可以成立,但結(jié)果可能不成立,在使用時(shí)需要注意(當(dāng)然,不排除將來支持)。比如:

          func?MakeChan[T?chan?bool?|?chan?int](c?T)?{
          ??_?=?make(T)?//?錯(cuò)誤
          ???_?=?new(T)?//?正確
          ??_?=?len(c)??//?正確
          }

          //?以下代碼無法編譯:
          //?cannot?range?over?c?(variable?of?type?T?constrained?by?[]string|map[int]string)?(T?has?no?structural?type)
          func?ForEach[T?[]string?|?map[int]string](c?T,?f?func(int,?string))?{
          ?for?i,?v?:=?range?c?{
          ??f(i,?v)
          ?}
          }

          ForEach 函數(shù)的簽名,你能看懂嗎?泛型確實(shí)讓 Go 復(fù)雜起來了,雖然語法允許,但建議大家以后寫泛型代碼時(shí)一定要盡量保證可讀性。




          往期推薦


          我是 polarisxu,北大碩士畢業(yè),曾在 360 等知名互聯(lián)網(wǎng)公司工作,10多年技術(shù)研發(fā)與架構(gòu)經(jīng)驗(yàn)!2012 年接觸 Go 語言并創(chuàng)建了 Go 語言中文網(wǎng)!著有《Go語言編程之旅》、開源圖書《Go語言標(biāo)準(zhǔn)庫》等。


          堅(jiān)持輸出技術(shù)(包括 Go、Rust 等技術(shù))、職場心得和創(chuàng)業(yè)感悟!歡迎關(guān)注「polarisxu」一起成長!也歡迎加我微信好友交流:gopherstudio

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

          手機(jī)掃一掃分享

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

          手機(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>
                  亚洲有码在线观看 | 综合亚洲色区 | 草逼福利 | 看操年轻小媳妇逼毛片视频 | 国产黄片手机在线观看 |