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, 我会尽快响应.
来源: https://www.cnblogs.com/yjf512/p/10917551.html