一边python,一边golang ! 时常因为工作切换语言造成了短路。container/list是golang语言内置的链表库。 对比其他语言的list,container/list该有的功能都有,就缺一个popLeft popRight方法。如果要实现pop方法需要去除value := list.Back() , 然后list.Remove(value) 。但这样不能保持操作的原子性。 解决的方法是用全局的互斥锁。
该文章写的有些乱,欢迎来喷 ! 另外文章后续不断更新中,请到原文地址查看更新。
下面是 container/list 包的基本用法.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#xiaorui.cc func (e *Element) Next() *Element //返回该元素的下一个元素,如果没有下一个元素则返回nil func (e *Element) Prev() *Element//返回该元素的前一个元素,如果没有前一个元素则返回nil。 func New() *List //返回一个初始化的list func (l *List) Back() *Element //获取list l的最后一个元素 func (l *List) Front() *Element //获取list l的第一个元素 func (l *List) Init() *List //list l初始化或者清除list l func (l *List) InsertAfter(v interface{}, mark *Element) *Element //在list l中元素mark之后插入一个值为v的元素,并返回该元素,如果mark不是list中元素,则list不改变。 func (l *List) InsertBefore(v interface{}, mark *Element) *Element//在list l中元素mark之前插入一个值为v的元素,并返回该元素,如果mark不是list中元素,则list不改变。 func (l *List) Len() int //获取list l的长度 func (l *List) MoveAfter(e, mark *Element) //将元素e移动到元素mark之后,如果元素e或者mark不属于list l,或者e==mark,则list l不改变。 func (l *List) MoveBefore(e, mark *Element)//将元素e移动到元素mark之前,如果元素e或者mark不属于list l,或者e==mark,则list l不改变。 func (l *List) MoveToBack(e *Element)//将元素e移动到list l的末尾,如果e不属于list l,则list不改变。 func (l *List) MoveToFront(e *Element)//将元素e移动到list l的首部,如果e不属于list l,则list不改变。 func (l *List) PushBack(v interface{}) *Element//在list l的末尾插入值为v的元素,并返回该元素。 func (l *List) PushBackList(other *List)//在list l的尾部插入另外一个list,其中l和other可以相等。 func (l *List) PushFront(v interface{}) *Element//在list l的首部插入值为v的元素,并返回该元素。 func (l *List) PushFrontList(other *List)//在list l的首部插入另外一个list,其中l和other可以相等。 func (l *List) Remove(e *Element) interface{}//如果元素e属于list l,将其从list中删除,并返回元素e的值。 |
需要说明的是,container/list默认不是线程安全的,应该说大多数语言自带的list都不能确保数据安全。 如果你想保证数据安全,那么可以使用Lock锁解决。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
#xiaorui.cc package main import ( "container/list" "fmt" ) func main() { // 生成队列 l := list.New() // 入队, 压栈 l.PushBack(1) l.PushBack(2) l.PushBack(3) l.PushBack(4) // 出队 v1 := l.Front() l.Remove(v1) fmt.Printf("%d\n", v1.Value) // 出栈 a1 := l.Back() l.Remove(a1) fmt.Printf("%d\n", a1.Value) } |
如果你是在goroutine协程环境下使用container/list链表,那么一定要记得加锁。 代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#xiaorui.cc #xiaorui.cc package main import ( "fmt" "sync" ) func main() { var l *sync.Mutex l = new(sync.Mutex) l.Lock() defer l.Unlock() fmt.Println("1") } |
使用container/list包结合sync的mutex互斥锁造了一个支持线程安全的链表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
package main import ( "container/list" "fmt" "sync" "time" ) type Queue struct { data *list.List } func NewQueue() *Queue { q := new(Queue) q.data = list.New() return q } func (q *Queue) push(v interface{}) { defer lock.Unlock() lock.Lock() q.data.PushFront(v) } func (q *Queue) pop() interface{} { defer lock.Unlock() lock.Lock() iter := q.data.Back() v := iter.Value q.data.Remove(iter) return v } func (q *Queue) dump() { for iter := q.data.Back(); iter != nil; iter = iter.Prev() { fmt.Println("item:", iter.Value) } } var lock sync.Mutex func main() { q := NewQueue() go func() { q.push("one") }() go func() { q.push("four") }() q.push("two") q.push("three") v := q.pop() fmt.Println("pop v:", v) fmt.Println("......") time.Sleep(1 * time.Second) q.dump() } |
上面那段go代码运行后的结果:
1 2 3 4 5 6 |
pop v: two ...... item: three item: one item: four |
有疑问加站长微信联系(非本文作者)