<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 類型約束那些事

          共 2368字,需瀏覽 5分鐘

           ·

          2021-11-30 23:42

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

          大家好,我是 polarisxu。

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

          請安裝最新的 tip 版本,方便驗證本文的內容。當然,也可以通過 https://gotipplay.golang.org/?在線驗證。

          01 語法變更

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

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

          不過目前已經確認,語法改成如下形式:

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

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

          02 額外用法

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

          看一個具體示例:

          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

          最后注釋的一行代碼,會編譯報錯:string does not satisfy int|float64

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

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

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

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

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

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

          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 函數的簽名:

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

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

          03 注意事項

          約束形式的多樣性,導致 Go 泛型語法一下子復雜起來:

          //?沒有任何約束
          func?add[T?any](x,?y?T)?T
          //?約束?Addble?(需要單獨定義)
          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

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

          func?MakeChan[T?chan?bool?|?chan?int](c?T)?{
          ??_?=?make(T)?//?錯誤
          ???_?=?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 函數的簽名,你能看懂嗎?泛型確實讓 Go 復雜起來了,雖然語法允許,但建議大家以后寫泛型代碼時一定要盡量保證可讀性。



          推薦閱讀


          福利

          我為大家整理了一份從入門到進階的Go學習資料禮包,包含學習建議:入門看什么,進階看什么。關注公眾號 「polarisxu」,回復?ebook?獲取;還可以回復「進群」,和數萬 Gopher 交流學習。

          瀏覽 42
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  夜夜撸成人 | 欧美操逼123 | 成人毛片18女人毛片免费96 | 亚洲经品无码 | 在线水蜜桃 |