返回顶部
首页 > 资讯 > 后端开发 > GO >解决golang中container/list包中的坑
  • 925
分享到

解决golang中container/list包中的坑

2024-04-02 19:04:59 925人浏览 薄情痞子
摘要

golang中list包用法可以参看这篇文章 但是list包中大部分对于e *Element进行操作的元素都可能会导致程序崩溃,其根本原因是e是一个Element类型的指针,当然其也

golang中list包用法可以参看这篇文章

但是list包中大部分对于e *Element进行操作的元素都可能会导致程序崩溃,其根本原因是e是一个Element类型的指针,当然其也可能为nil,但是Golang中list包中函数没有对其进行是否为nil的检查,变默认其非nil进行操作,所以这种情况下,便可能出现程序崩溃。

1.举个简单例子

Remove()函数


package main 
import (
 "container/list"
 "fmt"
)
 
func main() {
 l := list.New()
 l.PushBack(1)
 fmt.Println(l.Front().Value) //1
 value := l.Remove(l.Front())
 fmt.Println(value)            //1
 value1 := l.Remove(l.Front()) //panic: runtime error: invalid memory address or nil pointer dereference
 fmt.Println(value1)
}

从程序中可以直观的看出程序崩溃,原因是list中只有1个元素,但是要删除2个元素。但是再进一步查看一下原因,便会得出如下结果。

golang中Front()函数实现如下


func (l *List) Front() *Element {
    if l.len == 0 {
        return nil
    }
    return l.root.next
}

由此可见,当第一次删除之后。list的长度变为0,此时在调用l.Remove(l.Front()),其中l.Front()返回的是一个nil。

接下来再看golang中Remove()函数实现,该函数并没有判定e是否为nil,变直接默认其为非nil,直接对其进行e.list或者e.Value取值操作。

当e为nil时,这两个操作都将会造成程序崩溃,这也就是为什么上面程序会崩溃的原因。


func (l *List) Remove(e *Element) interface{} {
 if e.list == l {
  // if e.list == l, l must have been initialized when e was inserted
  // in l or l == nil (e is a zero Element) and l.remove will crash
  l.remove(e)
 }
 return e.Value
}

2.(l *list)PushBackList(other *list)

该函数用于将other list中元素添加在l list的后面。

基本实现思想是取出other中所有元素,将其顺次挂载在l列表中,但是golang中实现有问题

代码如下


func (l *List) PushBackList(other *List) {
 l.lazyInit()
 for i, e := other.Len(), other.Front(); i > 0; i, e = i-1, e.Next() {
  l.insertValue(e.Value, l.root.prev)
 }
}

其具体思想是首先获取other的长度n,然后循环n次取出其元素将其插入l中。问题就出现在循环n次,如果在这个过程中other的元素变化的话,例如其中有些元素被删除了,这就导致e的指针可能为nil,此时再利用e.Value取值,程序便会崩溃。

如下所示


package main
 
import (
 "container/list"
 "runtime"
)
 
func main() {
 runtime.GOMAXPROCS(8)
 l := list.New()
 ls := list.New()
 for i := 0; i < 10000; i++ {
  ls.PushBack(i)
 }
 go ls.Remove(l.Back())
 l.PushBackList(ls) //invalid memory address or nil pointer dereference
}

如程序中所示,再讲ls中元素添加到l过程中,如果ls中元素减少,程序便会崩溃。原因如上面分析。

建议:

在golang中如果对与list的操作只有串行操作,则只需要注意检查元素指针是否为nil便可避免程序崩溃,如果程序中会并发处理list中元素,建议对list进行加写(全局锁),然后再操作。注意,读写锁无法保证并行处理list时程序的安全性。

补充:golang list 链表

看代码吧~


package main 
import (
	"container/list"
	"fmt"
)
 
func main() {
	dataList := list.New()
 
	dataList.PushBack(1)	// 插入末尾
	dataList.PushBack(2)
	dataList.PushFront(3)	 // 插入表头
	dataList.PushBack(4)
	dataList.PushBack(5)
	m := dataList.PushBack(6)
	m1 := dataList.InsertBefore(7,m)	// 6 之前插入 7
	m2 := dataList.InsertAfter(8,m)	// 6 之后插入 8
 
	// 从链表头开始遍历
	for e := dataList.Front(); e != nil; e = e.Next() {
		fmt.Println(e.Value) // 打印值
	}
 
	fmt.Println("----------------------------------------")
 
	dataList.Remove(dataList.Front())	// 移除头部
	dataList.MoveBefore(m2, m)	// 将m2移动m之前
	dataList.MoveAfter(m1, m)
	dataList.Remove(m)	// 移除
 
	//PushBackList	// 插入列表
	//PushFrontList	//
 
	// 从链表头开始遍历
	for e := dataList.Front(); e != nil; e = e.Next() {
		fmt.Println(e.Value) // 打印值
	}
 
	fmt.Println("----------------------------------------")
 
 
	// 从链表尾开始遍历
	for e := dataList.Back(); e != nil; e = e.Prev() {
		fmt.Println(e.Value, " ")
	}
 
	fmt.Println("----------------------------------------")
	dataList.Init()	// 清空链表
	// 从链表头开始遍历
	for e := dataList.Front(); e != nil; e = e.Next() {
		fmt.Println(e.Value) // 打印值
	}
}

运行结果:

3
1
2
4
5
7
6
8
----------------------------------------
1
2
4
5
8
7
----------------------------------------
7  
8  
5  
4  
2  
1  
----------------------------------------

Process finished with exit code 0

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。如有错误或未考虑完全的地方,望不吝赐教。

您可能感兴趣的文档:

--结束END--

本文标题: 解决golang中container/list包中的坑

本文链接: https://lsjlt.com/news/124604.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 解决golang中container/list包中的坑
    golang中list包用法可以参看这篇文章 但是list包中大部分对于e *Element进行操作的元素都可能会导致程序崩溃,其根本原因是e是一个Element类型的指针,当然其也...
    99+
    2024-04-02
  • 基于golang中container/list包的用法说明
    list是一个双向链表 该结构具有链表的所有功能。 type Element type Element struct { Value interface{} ...
    99+
    2024-04-02
  • 解决Golang中ResponseWriter的一个坑
    在使用Context.ResponseWriter中的Set/WriteHeader/Write这三个方法时,使用顺序必须如下所示,否则会出现某一设置不生效的情况。 ctx.Re...
    99+
    2024-04-02
  • electron打包中的坑如何解决
    这篇文章主要讲解了“electron打包中的坑如何解决”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“electron打包中的坑如何解决”吧!问题一:css文件中图片加载失败问题描述问题是这样...
    99+
    2023-07-05
  • go中import包的坑如何解决
    这篇文章主要介绍“go中import包的坑如何解决”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“go中import包的坑如何解决”文章能帮助大家解决问题。方案一:使用GOROOT和GOPATH(以我...
    99+
    2023-07-02
  • 解决Golang 中使用WaitGroup的那点坑
    sync.WaitGroup对于Golang开发者来说并不陌生,其经常作为多协程之间同步的一种机制。用好它势必会让你事半功倍,但是一旦错用将引发问题。 关于WaitGroup的使用网...
    99+
    2024-04-02
  • Golang中JSON遇到的坑如何解决
    本篇内容主要讲解“Golang中JSON遇到的坑如何解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Golang中JSON遇到的坑如何解决”吧!空指针会被解析成字符串"null&qu...
    99+
    2023-07-05
  • go中import包的大坑解决方案
    目录方案一:使用GOROOT和GOPATH方案二:使用go.mod    最近开始使用Go/GoLand 在import 自定义包时出现...
    99+
    2022-06-07
    import GO 解决方案
  • electron打包中的巨坑解决记录
    目录吐槽问题一:css文件中图片加载失败问题描述解决过程补充问题二:无法使用cookie问题描述原因分析总结吐槽 从上周五到今天,我被electron打包折磨得死去活来,本来想让...
    99+
    2023-03-01
    electron打包坑解决 electron 打包
  • springcloudfeign传输List的坑及解决
    目录feign传输List的坑错误方法1错误方法2错误方法3feign调用传List接不到值feign传输List的坑 无法直接传输List 错误方法1 @RequestMappin...
    99+
    2024-04-02
  • Golang的strings.Split()坑怎么解决
    这篇文章主要介绍“Golang的strings.Split()坑怎么解决”,在日常操作中,相信很多人在Golang的strings.Split()坑怎么解决问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Gol...
    99+
    2023-06-30
  • java中怎么解决list集合做删除操作时的坑
    本篇内容主要讲解“java中怎么解决list集合做删除操作时的坑”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“java中怎么解决list集合做删除操作时的坑”吧!关于list集合做删除操作时的坑...
    99+
    2023-06-25
  • 怎么解决Java List的remove()方法踩坑
    这篇文章主要讲解了“怎么解决Java List的remove()方法踩坑”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么解决Java List的remove()方法踩坑”吧!Java的Li...
    99+
    2023-06-25
  • Golang时间处理中容易踩的坑分析解决
    目录简介类型时区小心有坑时间解析的使用场景时间操作获取当前时间时区设置时间格式化(时间类型转字符串)时间类型转时间戳时间戳转时间类型时间字符串转时间类型时间计算获取时间类型具体内容时...
    99+
    2023-01-11
    Golang时间处理踩坑解决 Go 时间处理
  • electron打包的坑如何解决
    这篇文章主要介绍“electron打包的坑如何解决”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“electron打包的坑如何解决”文章能帮助大家解决问题。两种方式,electron-builder打...
    99+
    2023-07-05
  • 解决spring jpa中update的坑
    spring jpa中update遇到的坑 使用jpa 自己编写update语句, 遇到问题: 1.在同一个service事物中,先执行保存,在执行更新,紧接着执行查询--查询结果为...
    99+
    2024-04-02
  • Pytorch中retain_graph的坑及解决
    目录Pytorch中retain_graph的坑Pytorch中有多次backward时需要retain_graph参数解决办法总结Pytorch中retain_graph的坑 在查...
    99+
    2023-02-21
    Pytorch中retain_graph retain_graph的坑 Pytorch retain_graph坑
  • 解决Java中new BigDecimal()的坑
    目录new BigDecimal()的坑关于BigDecimal用法1.实例 BigDecimal 对象2. BigDecimal 加减乘除3. Scale 属性操作4. compa...
    99+
    2024-04-02
  • vant3中使用List组件的一些坑
    目录使用vant3 List 组件过程中遇到的一些坑处理vant list使用报错的点总结使用vant3 List 组件过程中遇到的一些坑 1、接口错误的时候,大量重复请求。 可能接...
    99+
    2023-01-18
    vant3 List组件 vant3使用List组件 使用List组件的坑
  • golang中包无法引入问题解决
    目录前言问题背景问题现象问题解决1、强制开启GO111MODULE2、切换代理问题总结前言 刚接触golang不久,有些环境无法融会贯通,现在针对开发过程中遇到的问题做个排查记录 问...
    99+
    2023-03-19
    golang 包无法引入 golang 包引入
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作