attachments-2021-07-2ML4UdN060e7bccec3360.png

与Java比起来,golang是一门新兴的编程语言。Java经过26年的发展,生态已经非常完善。JDK也已经实现了各种丰富的容器供开发者使用。而golang除了语言自带的array、slice和map等数据结构之外,几乎没有实现任何其它的容器。

gocontainer借鉴了JDK的一些实现,并结合golang做了一定的创新。这个项目在github上开源,地址如下:


gocontainer概要介绍

gocontainer主要是参考JDK并结合golang自身的特点,为golang实现的一套容器库。gocontainer不依赖任何第三方软件包;套用HAProxy的宣传词"zero-copy",gocontainer是"zero-dependency"。

gocontainer不是线程安全的。这么设计出于几个原因:1、在不需要线程(goroutine)安全的环境中使用,性能更好;2、即使在需要线程(goroutine)安全的环境中使用,应用层也可以很容易的实现加锁同步;3、开始阶段,尽可能的简化gocontainer的设计与实现。后续的改进尽可能的基于社区的反馈来进行,而不是零君个人的各种猜想。

gocontainer v0.0.1版本实现了stack、queue、set、list(包含ArrayList和LinkedList)、priorityQueue以及linkedMap这几种容器。下面会对这几种容器分别做简要的介绍。更详细的介绍以及示例,请直接访问github上的开源项目:


如何使用gocontainer

使用gocontainer极其容易,如果你需要使用某个容器,只需要在代码中import相应的包,然后直接使用即可。下面是一个完整的使用arrayList的例子,

package main
import (
  "fmt"
  "github.com/ahrtr/gocontainer/list"
)
func main() {
  al := list.NewArrayList()
  al.Add(5) al.Add(6)
  al.Add(7)
  // Iterate all the elements
  fmt.Println("Iterate (method 1): ") 
  for i := 0; i < al.Len(); i++ {
     v, _ := al.Get(i)
     fmt.Printf(" Index: %d, value: %v\n", i, v)
  }
}


公共接口(Common Interface)

每一个容器都有一个对应的接口定义,对于上层开发者来说,只需要关心接口中定义的方法即可。因为所有的容器都包含一些签名完全相同的方法,所以就定义了一个公共的接口,如下:

// Interface is a type of collection, all containers should implement this interface.
type Interface interface {
// IsEmpty returns true if this container contains no elements.
IsEmpty() bool
// Clear removes all of the elements from this container.
Clear()
// Len is the number of elements in the container.
// Len() is also included in sort.Interface. Only golang 1.14 supports embedding of Interfaces with overlapping method sets,
// so let's add it in this interface in the future.
//Len() int
}

这里值得一提的是,零君原本想把方法Len()也加入这个公共接口,但由于有些容器实现了sort.Interface,而该接口中也包含方法Len()。这样同时实现了这个两个接口的“类”,就会包含重复的方法Len()。这种钻石型的“继承”结构,只有golang 1.14才支持,对于老版本的golang版本,编译时就会报错。由于目前很多开发者还是使用老版本的golang,所以零君暂时就没有将Len()加入该公共接口。


几种常用容器简洁

gocontainer中实现的几种常用容器的简介包含在下面的表格中:

容器名
介绍
stack
是一种后进先出的容器
queue
是一种先进先出的容器,典型的应用场景是消费者-生产者模型。
set
特点是容器内不允许包含重复的值。所以包含在容器中的值必须是可以用==比较的;更具体的来说,可以作为key存储在map中的类型,都可以存储在set中。
list
包含arrayList和linkedList两种类型。
priorityQueue
基于堆排序的一种队列。队列头的元素始终是优先级最高的元素。优先级的高低由数据的自然顺序(默认队列头是最小值),或者由上层应用提供的comparator来决定。
linkedMap
基于map和一个双向链表实现。map可以保证查询的速度,而双向链表保证了确定的遍历顺序。

这几种容器中,只有set、list和linkedMap支持遍历,其中list和linkedMap支持正向遍历和反向遍历。还是以list为例来说明,正向遍历除了使用上面例子中所示的for循环(i从0到size-1)的方法,还可以使用下面的方法:

// To iterate over a list (where l is an instance of list.Interface):
it, hasNext := l.Iterator()
var v interface{}
for hasNext {
v, hasNext = it()
// do something with v
}

同理,反向遍历list,除了使用for循环(i从size-1到0),还可以使用下面的方法:

// To iterate over a list in reverse order (where l is an instance of list.Interface):
it, hasPrev := l.ReverseIterator()
var v interface{}
for hasPrev {
v, hasPrev = it()
// do something with v
}


关于排序

因为list直接实现了接口sort.Interface,所以无论是arrayList还是linkedList,都可以直接使用golang自带的sort.Sort(data)进行排序。对于golang一些内置的数据类型(例如bool、数字、字符串等)默认是按照升序排列,如果想采取倒序,则使用:

sort.Sort(sort.Reverse(data))

对于list(包括arrayList和linkedList)和priorityQueue,都可以利用WithComparator方法传入一个Comparator。这样上层应用可以完全定制排序机制。

WithComparator(c gsort.Comparator) Interface


接口Comparator定义如下:

// Comparator imposes a total ordering on some collection of objects.
// Comparators can be passed to the construction function of a container(such as ArrayList, LinkedList or PriorityQueue) to allow precise control over the sort order.
type Comparator interface {
// Compare compares its two arguments for order.// It returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
Compare(v1 interface{}, v2 interface{}) (int, error)
}

这里就不举例说明了,具体请查看gocontainer在github上的说明与示例。

总结

本文简要介绍了开源项目gocontainer,以及其为golang实现几种常用的容器。目前该项目仍在不断的开发与完善之中,欢迎任何人提出任何建议,或者参与到该开源项目中。

程序员编程交流QQ群:805358732

如果你想用Python开辟副业赚钱,但不熟悉爬虫与反爬虫技术,没有接单途径,也缺乏兼职经验
关注下方微信公众号:Python编程学习圈,获取价值999元全套Python入门到进阶的学习资料以及教程,还有Python技术交流群一起交流学习哦。

attachments-2022-06-79zXno9862ad3438e1d90.jpeg