在go中的list表属于双向链表,表头部的prev和尾部的next同时指向一个相同的地址,从而实现了一个环。list的零值是一个准备使用的空列表。
源码:https://cs.opensource.google/go/go/+/refs/tags/go1.20.5:src/container/list/list.go
document:https://pkg.go.dev/container/list#pkg-overview
要使用list需要从container包引入。
list的方法
Next() : 返回下一个元素或nil
Prev(): 返回上一个元素或nil
Back(): 返回列表的最后一个元素,如果列表为空,则返回nil
Front(): 返回列表的首个元素,如果列表为空,则返回nil
Init(): 初始化或清空列表
InsertAfter(): 在某指定元素后插入
InsertBefore(): 在某指定元素前插入
Len(): 返回元素的个数,时间复杂度是O(1)
MoveToBack()、MoveToFront():将list中的某个元素移动到尾部/头部。如果元素不属于列表中的,则不会修改,元素必须不为nil。
MoveAfter(e,mark)、MoveBefore(e,mark): 将元素e移动到mark后面/前面,如果元素e或mark不属于list中的元素,或者e==mark,则不修改;e和mark不能是nil
PushBack()、PushFront()、Remove()见名知意
PushFrontList()、PushBackList(): 在列表的首部/尾部插入另外一个列表,他们不能为空。
方法示例:

package main import ( "container/list" "fmt" ) func main() { s := make([]int, 5) l := list.New() l2 := list.New().Init() fmt.Printf("%T %+[1]v %p\n", l, &l) fmt.Printf("%T %+[1]v %p\n", l2, &l2) l2.PushBack("gopher") l2.PushBack("come on") l.PushBack(2) l.PushFront("first") l.PushBack("你好吗") e := l.Front().Next() l.InsertAfter('c', e) l.InsertBefore(3.14, e) l.InsertBefore(s, e) l.PushBack("last") l.PushBackList(l2) // 将l2列表尾部加入到l列表中 e1 := l.Back().Prev().Prev() // 获取尾部的上一个的上一个元素 l.MoveToBack(e1) // 将“last”移动到尾部 l.MoveAfter(l.Back().Prev().Prev(), l.Front().Next()) // 将某个元素移动到某个元素后面 l.Remove(l.Front().Next()) // 移除某个元素 fmt.Printf("%T %+[1]v %p\n", l, &l) for i := l.Front(); i != nil; i = i.Next() { fmt.Printf("%T %[1]v\n", i) fmt.Println(i.Next()) } }
list结构体
示例:*list.List &{root:{next:0xc000076510 prev:0xc000076510 list:<nil> Value:<nil>} len:0} 0xc00000a028,这是一个空list的元数据,其中记录了next、prev、len等数据。
下面是一个示例

package main import ( "container/list" "fmt" ) func main() { s := make([]int, 5) l := list.New() fmt.Printf("%T %+[1]v %p\n", l, &l) l.PushBack(2) l.PushFront("first") l.PushBack("你好吗") e := l.Front().Next() l.InsertAfter('c', e) l.InsertBefore(3.14, e) l.InsertBefore(s, e) l.PushBack("last") fmt.Printf("%T %+[1]v %p\n", l, &l) for i := l.Front(); i != nil; i = i.Next() { fmt.Printf("%T %[1]v\n", i) } }
我在执行了上面的代码后,返回是这样的:
*list.List &{root:{next:0xc000076510 prev:0xc000076510 list:<nil> Value:<nil>} len:0} 0xc00000a028 *list.List &{root:{next:0xc0000765a0 prev:0xc000076690 list:<nil> Value:<nil>} len:7} 0xc00000a028 *list.Element &{0xc000076630 0xc000076510 0xc000076510 first} *list.Element &{0xc000076660 0xc0000765a0 0xc000076510 3.14} *list.Element &{0xc000076570 0xc000076630 0xc000076510 [0 0 0 0 0]} *list.Element &{0xc000076600 0xc000076660 0xc000076510 2} *list.Element &{0xc0000765d0 0xc000076570 0xc000076510 99} *list.Element &{0xc000076690 0xc000076600 0xc000076510 你好吗} *list.Element &{0xc000076510 0xc0000765d0 0xc000076510 last}
从返回中,可以看到头部元素的prev和尾部元素的next都指向了0xc000076510 地址,通过这个地址完成了list的闭环。下面我使用图来表达,地址简写为后三位表达:
疑问:
1、上面示例中,在遍历元素的时候,发现每次都会打印0xc000076510这个指针,这是个什么指针?为什么每个元素都包含?
答:因为在使用list.New()来创建一个列表的时候,是创建了一个 list.List
实例,而该实例的所有元素都是通过该实例的指针进行访问和操作的。
具体来说,每个元素都是 list.Element
类型的结构体,其中包含了 Value
字段表示节点的值,以及 Next()
和 Prev()
方法表示指向下一个节点和上一个节点的指针。第三个指针就是表达指向该元素所在的 list.List
实例的指针。所以每次打印都会相同。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2017-06-16 html操作