Go 提案:增加泛型版 Slices 和 Maps 新包
本文轉(zhuǎn)載自微信公眾號(hào)「腦子進(jìn)煎魚了」,作者陳煎魚。轉(zhuǎn)載本文請(qǐng)聯(lián)系腦子進(jìn)煎魚了公眾號(hào)。
大家好,我是煎魚。
現(xiàn)在是 2021 年 8 月份了,根據(jù) Go 語(yǔ)言發(fā)布周期的 2,8 原則。Go 1.17 即將發(fā)布,在寫這篇文章時(shí),現(xiàn)在已經(jīng)進(jìn)行到了 rc2:
這意味著離 Go1.18 釋出泛型的正式支持又近了一點(diǎn)點(diǎn),社區(qū)中討論泛型相關(guān)的周邊功能的聲音又多了起來(lái)。
今天要討論的泛型版功能支持也是如此,分別包含:map(#47330)、slice(#45955)、container/set(#47331) 三種通用類型的支持。
我們主要展開 maps 和 slices,其余的都大同小異,理解核心思想就好。
maps
該提案建議定義一個(gè)新的包 maps,它將提供可用于任何類型的 map 的函數(shù):
下面的描述側(cè)重于描述 API 的提供:
- package maps
- func Keys[K comparable, V any](m map[K]V) []K
- func Values[K comparable, V any](m map[K]V) []V
- func Equal[K, V comparable](m1, m2 map[K]V) bool
- func EqualFunc[K comparable, V1, V2 any](m1 map[K]V1, m2 map[K]V2, cmp func(V1, V2) bool) bool
- func Clear[K comparable, V any](m map[K]V)
- func Clone[K comparable, V any](m map[K]V) map[K]V
- func Add[K comparable, V any](dst, src map[K]V)
- func Filter[K comparable, V any](m map[K]V, keep func(K, V) bool)
- Keys:返回 map 的鍵值。這些鍵將是一個(gè)不確定的順序。
- Values:返回 map 值。這些值將以不確定的順序出現(xiàn)。
- Equal:匹配兩個(gè) map 是否包含相同的鍵/值對(duì)。
- EqualFunc:EqualFunc 與 Equal 類似,但使用 cmp 進(jìn)行數(shù)值比較。
- Clear:從 map 中清除所有條目,使其為空。
- Clone:返回一個(gè) map 的副本,這是一個(gè)淺層克隆。新的鍵和值使用普通的賦值來(lái)設(shè)置。
- Add:將 src 中的所有鍵/值對(duì)添加到 dst 中。當(dāng) src 中的一個(gè)鍵已經(jīng)存在于 dst 中時(shí),dst 中的值將被 src 中的鍵相關(guān)的值覆蓋。
- Filter:過(guò)濾器從 map 中刪除任何 keep 返回結(jié)果為 false 的鍵/值對(duì)。
slice
該提案建議定義一個(gè)新的包 slices,它將提供可用于任何類型的 slice 的函數(shù):
下面的描述側(cè)重于描述 API 的提供:
- package slices
- import "constraint"
- func Equal[T comparable](s1, s2 []T) bool
- func EqualFunc[T1, T2 any](s1 []T1, s2 []T2, eq func(T1, T2) bool) bool
- func Compare[T constraints.Ordered](s1, s2 []T) int
- func CompareFunc[T any](s1, s2 []T, cmp func(T, T) int) int
- func Index[T comparable](s []T, v T) int
- func IndexFunc[T any](s []T, f func(T) bool) int
- func Contains[T comparable](s []T, v T) bool
- func Insert[S constraints.Slice[T], T any](s S, i int, v ...T) S
- func Delete[S constraints.Slice[T], T any](s S, i, j int) S
- func Clone[S constraints.Slice[T], T any](s S) S
- Equal:檢查兩個(gè)切片是否相等,以長(zhǎng)度和元素值來(lái)比較。
- EqualFunc:檢查兩個(gè)切片是否相等,以所傳入的匹配函數(shù)來(lái)比較。
- Compare/CompareFunc:
- Compare 比較兩個(gè)切片 s1 和 s2 的元素。
- CompareFunc 與 Compare 類似,在每一對(duì)元素上使用所傳入的比較函數(shù)。
- Index:
- Index 返回值 v 在切片 s 中第一次出現(xiàn)的索引,如果不存在,則返回-1。
- IndexFunc 返回滿足f(c)的第一個(gè)元素在s中的索引,如果沒(méi)有則返回-1。
- Contains:檢查值 v 是否存在于切片 s 中。
插入、刪除、克隆的 API 比較常見,這里我就不展開了。在通用類型的切片有一些比較特殊的 API:
- func Compact[S constraints.Slice[T], T comparable](s S) S
- func CompactFunc[S constraints.Slice[T], T any](s S, cmp func(T, T) bool) S
- func Grow[S constraints.Slice[T], T any](s S, n int) S
- func Clip[S constraints.Slice[T], T any](s S) S
- Compact/CompactFunc:
- Compact 將連續(xù)運(yùn)行的相等元素替換為單一的副本。這就像 Unix 中的 uniq 命令。會(huì)直接修改切片 s 的內(nèi)容,不會(huì)重新創(chuàng)建一個(gè)。
- CompactFunc 與 Compact 方法類似,但是使用一個(gè)比較函數(shù)來(lái)匹配。
- Grow:如果有必要,Grow 會(huì)增長(zhǎng)切片的容量,以保證另外 n 個(gè)元素的空間。在 Grow(n) 之后,至少有 n 個(gè)元素可以被添加到分片中而不需要再分配。如果 n 是負(fù)數(shù)或者太大,無(wú)法分配內(nèi)存,Grow 將陷入恐慌。
- Clip:從切片中移除未使用的容量,返回s[:len(s):len(s)]。
總結(jié)
如果這些提議被接受,這幾個(gè)新包將被包含在實(shí)現(xiàn)泛型后的第一個(gè)Go版本中(我們目前預(yù)計(jì)將是Go 1.18)。
從issues 的討論來(lái)看,通用類型的新包支持很大概率會(huì)實(shí)現(xiàn),主要爭(zhēng)議在實(shí)現(xiàn)細(xì)節(jié),例如:性能、命名、規(guī)范等。
實(shí)現(xiàn)后值得期待,又是一次生產(chǎn)力的優(yōu)化!