跳到主要内容
版本:2.10.x(Latest)

泛型链表(推荐使用)

v2.10 版本开始,glist 提供了泛型链表 TList[T],提供类型安全的双向链表操作。

基本使用

package main

import (
"fmt"
"github.com/gogf/gf/v2/container/glist"
)

func main() {
// 创建一个int类型的泛型链表
l := glist.NewT[int]()

// 从尾部添加元素
l.PushBack(1)
l.PushBack(2)
l.PushBack(3)

// 从头部添加元素
l.PushFront(0)

// 获取长度
fmt.Println("Length:", l.Len()) // 输出: Length: 4

// 获取首尾元素
fmt.Println("Front:", l.Front().Value) // 输出: Front: 0
fmt.Println("Back:", l.Back().Value) // 输出: Back: 3

// 从头部弹出元素
front := l.PopFront()
fmt.Println("PopFront:", front) // 输出: PopFront: 0

// 遍历链表
l.IteratorAsc(func(e *glist.TElement[int]) bool {
fmt.Println("Element:", e.Value)
return true
})
}

链表遍历

泛型链表支持正序和逆序遍历。

package main

import (
"fmt"
"github.com/gogf/gf/v2/container/glist"
)

func main() {
l := glist.NewTFrom[string]([]string{"a", "b", "c", "d", "e"})

// 正序遍历
fmt.Println("Ascending:")
l.IteratorAsc(func(e *glist.TElement[string]) bool {
fmt.Println(e.Value)
return true
})

// 逆序遍历
fmt.Println("Descending:")
l.IteratorDesc(func(e *glist.TElement[string]) bool {
fmt.Println(e.Value)
return true
})
}

泛型链表特点

  1. 类型安全:在编译期就能发现类型错误,避免运行时类型断言失败。
  2. 高效操作:支持O(1)时间复杂度的首尾插入和删除操作。
  3. 更好的IDE支持:IDE能够提供更准确的代码补全和类型提示。
提示

推荐在新项目中使用泛型链表 TList[T],它提供了更好的类型安全性和开发体验。

传统链表类型

下面介绍传统的链表类型,这些类型在旧版本中被广泛使用,仍然完全支持。

基础使用

package main

import (
"fmt"
"github.com/gogf/gf/v2/container/glist"
)

func main() {
// Not concurrent-safe in default.
l := glist.New()

// Push
l.PushBack(1) //从后面插入值
l.PushBack(2) //从后面插入值
e := l.PushFront(0) //从前面插入值

// Insert
l.InsertBefore(e, -1) //从0的前面插入值
l.InsertAfter(e, "a") //从0的后面插入值
fmt.Println(l)

// Pop Pop 出栈后,从list里移除
fmt.Println(l.PopFront()) // 从前面出栈,返回出栈的值
fmt.Println(l.PopBack()) //从后面出栈
fmt.Println(l)

// All
fmt.Println(l.FrontAll()) //正序返回一个复本
fmt.Println(l.BackAll()) //逆序返回一个复本

// Output:
// [-1,0,"a",1,2]
// -1
// 2
// [0,"a",1]
// [0 "a" 1]
// [1 "a" 0]
}

链表遍历

该示例中我们将通过读锁和写锁遍历一个并发安全的链表,分别通过 RLockFuncLockFunc 实现。执行后,输出结果为:

package main

import (
"container/list"
"fmt"
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/container/glist"
)

func main() {
// concurrent-safe list.
l := glist.NewFrom(garray.NewArrayRange(1, 9, 1).Slice(), true)
fmt.Println(l)
// iterate reading from head.
l.RLockFunc(func(list *list.List) {
length := list.Len()
if length > 0 {
for i, e := 0, list.Front(); i < length; i, e = i+1, e.Next() {
fmt.Print(e.Value)
}
}
})
fmt.Println()
// iterate reading from tail.
l.RLockFunc(func(list *list.List) {
length := list.Len()
if length > 0 {
for i, e := 0, list.Back(); i < length; i, e = i+1, e.Prev() {
fmt.Print(e.Value)
}
}
})

fmt.Println()

// iterate reading from head using IteratorAsc.
l.IteratorAsc(func(e *glist.Element) bool {
fmt.Print(e.Value)
return true
})
fmt.Println()
// iterate reading from tail using IteratorDesc.
l.IteratorDesc(func(e *glist.Element) bool {
fmt.Print(e.Value)
return true
})

fmt.Println()

// iterate writing from head.
l.LockFunc(func(list *list.List) {
length := list.Len()
if length > 0 {
for i, e := 0, list.Front(); i < length; i, e = i+1, e.Next() {
if e.Value == 6 {
e.Value = "M"
break
}
}
}
})
fmt.Println(l)

// Output:
// [1,2,3,4,5,6,7,8,9]
// 123456789
// 987654321
// 123456789
// 987654321
// [1,2,3,4,5,M,7,8,9]

Push* 元素项入栈

package main

import (
"fmt"
"github.com/gogf/gf/v2/container/glist"
"github.com/gogf/gf/v2/frame/g"
)

func main() {
l := glist.NewFrom(g.Slice{1, 2, 3, 4, 5})

l.PushBack(6)
fmt.Println(l)

l.PushFront(0)
fmt.Println(l)

// 正数从右边入栈
l.PushBacks(g.Slice{7, 8})
fmt.Println(l)

// 负数从左边入栈
l.PushFronts(g.Slice{-1, -2})
fmt.Println(l)

l.PushFrontList(glist.NewFrom(g.Slice{"a", "b", "c"}))
l.PushBackList(glist.NewFrom(g.Slice{"d", "e", "f"}))
fmt.Println(l)

// Output:
// [1,2,3,4,5,6]
// [0,1,2,3,4,5,6]
// [0,1,2,3,4,5,6,7,8]
// [-2,-1,0,1,2,3,4,5,6,7,8]
// ["a","b","c",-2,-1,0,1,2,3,4,5,6,7,8,"d","e","f"]

}

Pop* 元素项出栈

package main

import (
"fmt"
"github.com/gogf/gf/v2/container/glist"
"github.com/gogf/gf/v2/frame/g"
)

func main() {
l := glist.NewFrom(g.Slice{1, 2, 3, 4, 5, 6, 7, 8, 9})

fmt.Println(l.PopBack())
fmt.Println(l.PopBacks(2))
fmt.Println(l.PopFront())
fmt.Println(l.PopFronts(2))

fmt.Println(glist.NewFrom(g.Slice{"a", "b", "c", "d"}).PopFrontAll())
fmt.Println(glist.NewFrom(g.Slice{"a", "b", "c", "d"}).PopBackAll())

// Output:
// 9
// [8 7]
// 1
// [2 3]
// [4,5,6]
// [a b c d]
// [d c b a]
}

Move*/Insert* 元素项移动、插入

package main

import (
"fmt"
"github.com/gogf/gf/v2/container/glist"
"github.com/gogf/gf/v2/frame/g"
)

func main() {
l := glist.NewFrom(g.Slice{1, 2, 3, 4, 5, 6, 7, 8, 9})

l.MoveToBack(l.Front()) //将第一个元素(1)移动最右边 [2,3,4,5,6,7,8,9,1]
l.MoveToFront(l.Back().Prev()) //将最后一项的前一个元素(9)移动最左边 [9,2,3,4,5,6,7,8,1]
fmt.Println(l)

// 将2到栈首元素的前面
l.MoveBefore(l.Front().Next(), l.Front())
// 将8到栈尾元素的后面
l.MoveAfter(l.Back().Prev(), l.Back())
fmt.Println(l)

// 在栈尾元素前插入新元素
l.InsertBefore(l.Back(), "a")
// 在栈首元素后插入新元素
l.InsertAfter(l.Front(), "b")

// Output:
// [9,2,3,4,5,6,7,8,1]
// [2,9,3,4,5,6,7,1,8]
// [2,"b",9,3,4,5,6,7,1,"a",8]
}

Join 元素项串连

package main

import (
"fmt"
"github.com/gogf/gf/v2/container/glist"
"github.com/gogf/gf/v2/frame/g"
)

func main() {
var l glist.List
l.PushBacks(g.Slice{"a", "b", "c", "d"})

fmt.Println(l.Join(","))

// Output:
// a,b,c,d
}

Remove* 元素项移除

package main

import (
"fmt"
"github.com/gogf/gf/v2/container/glist"
"github.com/gogf/gf/v2/frame/g"
)

func main() {
l := glist.NewFrom(g.Slice{0, 1, 2, 3, 4, 5, 6, 7, 8, 9})
fmt.Println(l)

fmt.Println(l.Remove(l.Front()))
fmt.Println(l)

l.Removes([]*glist.Element{l.Front(), l.Front().Next()})
fmt.Println(l)

l.RemoveAll()
fmt.Println(l)

// Output:
// [0,1,2,3,4,5,6,7,8,9]
// 0
// [1,2,3,4,5,6,7,8,9]
// [3,4,5,6,7,8,9]
// [] }

JSON 序列化/反序列

glist 容器实现了标准库 json 数据格式的序列化/反序列化接口。

  • Marshal
package main

import (
"encoding/json"
"fmt"
"github.com/gogf/gf/v2/container/glist"
"github.com/gogf/gf/v2/frame/g"
)

func main() {
type Student struct {
Id int
Name string
Scores *glist.List
}
s := Student{
Id: 1,
Name: "john",
Scores: glist.NewFrom(g.Slice{100, 99, 98}),
}
b, _ := json.Marshal(s)
fmt.Println(string(b))

// Output:
// {"Id":1,"Name":"john","Scores":[100,99,98]}
}
  • Unmarshal
package main


import (
"encoding/json"
"fmt"
"github.com/gogf/gf/v2/container/glist"
)


func main() {
b := []byte(`{"Id":1,"Name":"john","Scores":[100,99,98]}`)
type Student struct {
Id int
Name string
Scores *glist.List
}
s := Student{}
json.Unmarshal(b, &s)
fmt.Println(s)

// Output:
// {1 john [100,99,98]}
}