collection包1.1.0都升級了什麼功能
jianfengye/collection(https://github.com/jianfengye/collection) 這個包喜迎第一個子版本升級,從1.0.1升級到了1.1.0。這次還是做了不少改動的。
支援int32
這個需求是這個issue提出的: https://github.com/jianfengye/collection/issues/10
主要是在protobuf 生成的go程式碼裡面是int32,int64的。
增加一個型別的陣列其實是很方便的事情了,只需要寫一個Int32Collection的struct, 基於AbsCollection,實現幾個必要的函式就可以了。
package collection
import (
"errors"
"fmt"
)
type Int32Collection struct {
AbsCollection
objs []int32
}
func compareInt32(i interface{}, i2 interface{}) int {
int1 := i.(int32)
int2 := i2.(int32)
if int1 > int2 {
return 1
}
if int1 < int2 {
return -1
}
return 0
}
// NewInt32Collection create a new Int32Collection
func NewInt32Collection(objs []int32) *Int32Collection {
arr := &Int32Collection{
objs: objs,
}
arr.AbsCollection.Parent = arr
arr.SetCompare(compareInt32)
return arr
}
...
實現延遲複製
這個是有一個讀者在公眾號留言提醒的。之前1.0.1版本的collection在new的時候直接將slice進行copy一份,是出於安全的考慮,Collection的使用一定不能修改到原有的slice。現在1.1.0在newCollection的時候並不複製slice,而是在需要對slice進行亂序或者變更操作的時候進行一次Copy操作。而我把Copy操作的時間也放到各個具體實現類中了。
於是ICollection多實現了一個Copy方法,它會把當前Collection的Slice複製一份出來。然後在AbsCollection中記錄一個是否已經拷貝的標記,isCopied,對於那些對原陣列進行操作的方法會根據這個標記,如果之前沒有複製,就複製一份,再進行操作
func (arr *AbsCollection) Insert(index int, obj interface{}) ICollection {
if arr.Err() != nil {
return arr
}
if arr.Parent == nil {
panic("no parent")
}
if arr.isCopied == false {
arr.Copy()
arr.isCopied = true
}
return arr.Parent.Insert(index, obj)
}
這樣就實現了延遲拷貝的功能。
實現了SetIndex的方法
這個方法和Index方法是對應的,將陣列的某個元素進行設定。
這個方法的具體實現也在實現類中實現了,特別是對ObjCollection的SetIndex實現還是需要reflect進行繞的,其他的COllection不需要使用反射。
func (arr *ObjCollection) SetIndex(i int, val interface{}) ICollection {
arr.objs.Index(i).Set(reflect.ValueOf(val))
return arr
}
Sort實現了快速排序
這個是這個issue提出的 https://github.com/jianfengye/collection/issues/9
之前的Sort我是使用氣泡排序實現的,確實效率有欠考慮。
這次將Sort進行了快排實現。由於已經又了SetIndex, Index, 等方法,所以可以這個快排可以直接在AbsCollection中實現就行了。
func (arr *AbsCollection) qsort(left, right int, isAscOrder bool) {
tmp := arr.Index(left)
p := left
i, j := left, right
for i <= j {
for j >= p {
c, err := arr.Index(j).Compare(tmp)
if err != nil {
arr.SetErr(err)
return
}
if isAscOrder && c >= 0 {
j--
continue
}
if !isAscOrder && c <= 0 {
j--
continue
}
break
}
if j >= p {
t, _ := arr.Index(j).ToInterface()
arr.SetIndex(p, t)
p = j
}
for i <= p {
c, err := arr.Index(i).Compare(tmp)
if err != nil {
arr.SetErr(err)
return
}
if isAscOrder && c <= 0 {
i++
continue
}
if !isAscOrder && c >= 0 {
i++
continue
}
break
}
if i <= p {
t, _ := arr.Index(i).ToInterface()
arr.SetIndex(p, t)
p = i
}
}
t, _ := tmp.ToInterface()
arr.SetIndex(p, t)
if p-left > 1 {
arr.qsort(left, p-1, isAscOrder)
}
if right-p > 1 {
arr.qsort(p+1, right, isAscOrder)
}
}
func (arr *AbsCollection) Sort() ICollection {
if arr.Err() != nil {
return arr
}
if arr.compare == nil {
return arr.SetErr(errors.New("sort: compare must be set"))
}
if arr.isCopied {
arr.qsort(0, arr.Count()-1, true)
return arr
}
arr.Copy()
return arr.Sort()
}
compare函式進行傳遞
之前IMix的compare函式一定都需要呼叫SetCompare才能設定,現在如果這個IMix是從Collection進行建立的,比如Collection.Index(xx) IMix, 返回的IMix就直接將Collection中設定的compare函式直接傳遞過來。
這樣在使用過程中方便了不少。
我也將各個型別的compare函式都整理在具體實現類的頭部
func compareInt32(i interface{}, i2 interface{}) int
func compareInt64(i interface{}, i2 interface{}) int
func compareInt(i interface{}, i2 interface{}) int
func compareString(a interface{}, b interface{}) int
...
總結
1.1.0版本主要是根據issue反饋修復了一些使用和效能上的優化點。總體覺得已經可以發一個小版本了,於是打上了1.1.0的tag。
該專案目前也有277個star了,歡迎在業務上試用 jianfengye/collection(https://github.com/jianfengye/collection) 這個包,有問題請直接提issue,我會盡快響應。