1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Go 泛型包 slices 來了

        共 4721字,需瀏覽 10分鐘

         ·

        2021-12-09 13:11

        閱讀本文大概需要 10?分鐘。

        大家好,我是 polarisxu。

        前段時間,Russ Cox 明確了泛型相關(guān)的事情,原計劃在標準庫中加入泛型相關(guān)的包,改放到 golang.org/x/exp 下。

        目前,Go 泛型的主要設(shè)計者 ianlancetaylor 完成了 slices 和 maps 包的開發(fā),代碼提交到了 golang.org/x/exp 中,如果經(jīng)過使用、討論等,社區(qū)認可后,預(yù)計在 1.19 中會合入標準庫中。

        今天,通過學習 slices 包,掌握 Go 泛型的使用方法。

        01 為什么增加 slices 包

        標準庫有 bytes 和 strings 包,分別用來處理 []byte 和 string 類型,提供了眾多方便的函數(shù),但對普通的 slice,卻沒有相關(guān)的包可以使用。

        比如 bytes 和 strings 都有 Index 函數(shù),用來在 []byte 或 string 查找某個 byte 或字符串的索引。對于普通的 slice,沒法寫一大堆包來處理,只能用戶自己實現(xiàn),這也是沒有泛型的弊端。

        提供 bytes 和 strings,主要是因為它們使用頻率高

        現(xiàn)在有了泛型,可以實現(xiàn)一些便利的 slice 操作方法,必須要針對某一個具體類型的 slice 都實現(xiàn)一遍相同的功能。

        02 constraints 包

        繼續(xù)講解 slices 包之前,先看看 contraints 包。

        該包定義了一組用于類型參數(shù)(泛型)的有用約束,這個包已經(jīng)確定在 Go 1.18 標準庫中包含,截止目前(2021.11.27),該包定義了 6 個約束類型:

        //?Signed?is?a?constraint?that?permits?any?signed?integer?type.
        //?If?future?releases?of?Go?add?new?predeclared?signed?integer?types,
        //?this?constraint?will?be?modified?to?include?them.
        type?Signed?interface?{
        ?~int?|?~int8?|?~int16?|?~int32?|?~int64
        }

        //?Unsigned?is?a?constraint?that?permits?any?unsigned?integer?type.
        //?If?future?releases?of?Go?add?new?predeclared?unsigned?integer?types,
        //?this?constraint?will?be?modified?to?include?them.
        type?Unsigned?interface?{
        ?~uint?|?~uint8?|?~uint16?|?~uint32?|?~uint64?|?~uintptr
        }

        //?Integer?is?a?constraint?that?permits?any?integer?type.
        //?If?future?releases?of?Go?add?new?predeclared?integer?types,
        //?this?constraint?will?be?modified?to?include?them.
        type?Integer?interface?{
        ?Signed?|?Unsigned
        }

        //?Float?is?a?constraint?that?permits?any?floating-point?type.
        //?If?future?releases?of?Go?add?new?predeclared?floating-point?types,
        //?this?constraint?will?be?modified?to?include?them.
        type?Float?interface?{
        ?~float32?|?~float64
        }

        //?Complex?is?a?constraint?that?permits?any?complex?numeric?type.
        //?If?future?releases?of?Go?add?new?predeclared?complex?numeric?types,
        //?this?constraint?will?be?modified?to?include?them.
        type?Complex?interface?{
        ?~complex64?|?~complex128
        }

        //?Ordered?is?a?constraint?that?permits?any?ordered?type:?any?type
        //?that?supports?the?operators?=?>.
        //?If?future?releases?of?Go?add?new?ordered?types,
        //?this?constraint?will?be?modified?to?include?them.
        type?Ordered?interface?{
        ?Integer?|?Float?|?~string
        }

        前面 3 個是整型相關(guān)類型約束,F(xiàn)loat 是浮點型約束,Complex 是負數(shù)類型約束,而 Ordered 表示支持排序的類型約束,表示支持大小比較的類型。

        之前文章:《Go泛型系列:Go1.18 類型約束那些事》提到,約束語法變更了,一個是 | 符號,一個是 ~,上面定義中,很多地方都用到了 ~ 符號,它表示出了類型自身,底層類型是它的類型也適用該約束。

        03 slices 包詳解

        目前,slices 包有 14 個函數(shù),可以分成幾組:

        • slice 比較
        • 元素查找
        • 修改 slice
        • 克隆 slice

        其中,修改 slice 分為插入元素、刪除元素、連續(xù)元素去重、slice 擴容和縮容。

        slice 比較

        比較兩個 slice 中的元素,細分為是否相等和普通比較:

        func?Equal[E?comparable](s1,?s2?[]E)?bool
        func?EqualFunc[E1,?E2?any](s1?[]E1,?s2?[]E2,?eq?func(E1,?E2)?bool)?bool
        func?Compare[E?constraints.Ordered](s1,?s2?[]E)?int
        func?CompareFunc[E1,?E2?any](s1?[]E1,?s2?[]E2,?cmp?func(E1,?E2)?int)?int

        其中 comparable 約束是語言實現(xiàn)的(因為很常用),表示可比較約束(相等與否的比較)。主要,其中的 E、E1、E2 等,只是泛型類型表示,你定義時,可以用你喜歡的,比如 T、T1、T2 等。

        看一個具體的實現(xiàn):

        func?Equal[E?comparable](s1,?s2?[]E)?bool?{
        ?if?len(s1)?!=?len(s2)?{
        ??return?false
        ?}
        ?for?i,?v1?:=?range?s1?{
        ??v2?:=?s2[i]
        ??if?v1?!=?v2?{
        ???return?false
        ??}
        ?}
        ?return?true
        }

        沒有什么特別的,只不過把 s1、s2 當成同類型的 slice 進行操作而已。

        元素查找

        在 slice 中查找某個元素,分為普通的所有查找和包含判斷:

        func?Index[E?comparable](s?[]E,?v?E)?int
        func?IndexFunc[E?any](s?[]E,?f?func(E)?bool)?int
        func?Contains[E?comparable](s?[]E,?v?E)?bool

        其中,IndexFunc 的類型參數(shù)沒有使用任何約束(即用的 any),說明查找是通過 f 參數(shù)進行的,它的實現(xiàn)如下:

        func?IndexFunc[E?any](s?[]E,?f?func(E)?bool)?int?{
        ?for?i,?v?:=?range?s?{
        ??if?f(v)?{
        ???return?i
        ??}
        ?}
        ?return?-1
        }

        參數(shù) f 是一個函數(shù),它接收一個參數(shù),類型是 E,是一個泛型,和 IndexFunc 的第一個參數(shù)類型 []E 的元素類型保持一致即可,因此可以直接將遍歷 s 的元素傳遞給 f。

        修改 slice

        一般不建議做相關(guān)操作,因為性能較差。如果有較多這樣的需求,可能需要考慮更換數(shù)據(jù)結(jié)構(gòu)。

        //?往?slice?的位置?i?處插入元素(可以多個)
        func?Insert[S?~[]E,?E?any](s?S,?i?int,?v?...E)?S
        //?刪除?slice?中?i?到?j?的元素,即刪除?s[i:j]?元素
        func?Delete[S?~[]E,?E?any](s?S,?i,?j?int)?S
        //?將連續(xù)相等的元素替換為一個,類似于 Unix 的 uniq 命令。Compact 修改切片的內(nèi)容,它不會創(chuàng)建新切片
        func?Compact[S?~[]E,?E?comparable](s?S)?
        func?CompactFunc[S?~[]E,?E?any](s?S,?eq?func(E,?E)?bool)?S
        //?增加?slice?的容量,至少增加?n?個
        func?Grow[S?~[]E,?E?any](s?S,?n?int)?S
        //?移除沒有使用的容量,相當于縮容
        func?Clip[S?~[]E,?E?any](s?S)?S

        以上類型約束都包含了兩個:

        • S ~[]E:表明這是一個泛型版 slice,這是對 slice 的約束。注意 [] 前面的 ~,表明支持自定義 slice 類型,如 type myslice []int
        • E any 或 E comparable:對上面 slice 元素類型的約束。

        克隆 slice

        即獲得 slice 的副本,會進行元素拷貝,注意,slice 中元素的拷貝是淺拷貝,非值類型不會深拷貝。

        func?Clone[S?~[]E,?E?any](s?S)?S?{
        ?//?Preserve?nil?in?case?it?matters.
        ?if?s?==?nil?{
        ??return?nil
        ?}
        ?return?append(S([]E{}),?s...)
        }

        04 總結(jié)

        因為泛型的存在,同樣的功能,對不同類型的 slice 再也不用寫多份代碼。因為一些功能很常見,因此 Go 官方將其封裝,將來會在標準庫中提供。

        出于謹慎考慮,slices 包不會在 1.18 中包含,如果你需要用到 slices 中的功能,可以采用從 slices 代碼中復(fù)制的方式,個人覺得依賴 golang.org/x/exp 還是不太好。

        slices 源碼地址:https://github.com/golang/exp/blob/master/slices/slices.go。



        推薦閱讀


        福利

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

        瀏覽 37
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

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

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            污网站免费在线观看 | 国产对白叫床清晰在线播放图片 | 四虎永久在线免费观看 | 国产精品视频一区二区三区 | 欧美性掹交XXXX乱大交3 黑人爱爱 | 三级视频网址 | 好大屌免费视频 | 操女生逼网站 | 91精品国产入口 | 他每挺进一下女人就呻吟 |