Go的List操作上的一个小“坑”
转自http://sharecore.net/blog/2014/01/09/the-trap-in-golang-list/
一直想不清楚一个问题,简单设计的东西到底是“坑多”还是“坑少”呢? 复杂的设计,考虑的太全面,使用起来更麻烦,使用者容易陷入乱,落入自身的陷阱;而简单的设计呢,在许多方面上又顾及不周,如果使用者对其“设计”没仔细研究,或者其实现本身又是一个黑盒子,也容易掉入到设计本身遗留下来的“陷阱”。下面是我刚开始使用Go写代码时碰到的一个小“坑”,这个“坑”的原因我归结为后者。
这个“小坑”来自于go的container/list package的使用上。导致“坑”的代码大概如下所示:
package main import (
"container/list"
"fmt"
) func main() {
//初始化一个list
l := list.New()
l.PushBack()
l.PushBack()
l.PushBack()
l.PushBack() fmt.Println("Before Removing...")
//遍历list,删除元素
for e := l.Front(); e != nil; e = e.Next() {
fmt.Println("removing", e.Value)
l.Remove(e)
}
fmt.Println("After Removing...")
//遍历删除完元素后的list
for e := l.Front(); e != nil; e = e.Next() {
fmt.Println(e.Value)
}
}
以上代码很简单,按常理来看,应该能得到正确的结果,list最后将会被清空。可事实却完全不是这样,执行后结果如下:
Before Removing...
removing
After Removing...
从结果可以看出,list根本没有清空,而只是删除了第一个元素。这是为何?原因就在container/list package的实现上了。这应该是我见过的实现最简单list了,出去注释也就100来行实现代码,而且它不只是一个简单链表,而且可以当做stack,当做queue来使用。
下面是Remove方法的代码:
// remove removes e from its list, decrements l.len, and returns e.
func (l *List) remove(e *Element) *Element {
e.prev.next = e.next
e.next.prev = e.prev
e.next = nil // avoid memory leaks
e.prev = nil // avoid memory leaks
e.list = nil
l.len--
return e
}
这下问题原因就明显了,就出现在e.next = nil 这行代码上。当执行玩remove,e.next就变成了nil,list遍历当然也就终止了。找出问题的原因,我们就容易找到workaround的办法了,将e.next用中间变量保存起来就OK了,代码如下:
package main import (
"container/list"
"fmt"
) func main() {
l := list.New()
l.PushBack()
l.PushBack("asd")
l.PushBack()
l.PushBack()
fmt.Println("Before Removing...")
var n *list.Element
for e := l.Front(); e != nil; e = n {
fmt.Println("removing", e.Value)
n = e.Next()
l.Remove(e)
}
fmt.Println("After Removing...")
for e := l.Front(); e != nil; e = e.Next() {
fmt.Println(e.Value)
}
}
正常结果输出:
Before Removing...
removing
removing
removing
removing
After Removing...
Go的List操作上的一个小“坑”的更多相关文章
- Jedis线上的一个小坑:Redis有并发访问的数据错乱的问题
问题现象: 业务数据有错乱,A的一些数据有好几个都是B的数据 这些业务数据在保存在Redis缓存中,怀疑是并发情况下Jedis错乱的问题 原因分析: JedisUtil里面在使用完Jedis 后释放资 ...
- java操作xml的一个小例子
最近两天公司事比较多,这两天自己主要跟xml打交道,今天更一下用java操作xml的一个小例子. 原来自己操作xml一直用这个包:xstream-1.4.2.jar.然后用注解的方式,很方便,自己只要 ...
- go的变量redeclare的问题,golang的一个小坑
go的变量声明有几种方式: 1 通过关键字 var 进行声明 例如:var i int 然后进行赋值操作 i = 5 2 最简单的,通过符号 := 进行声明和赋值 例如: i:=5 golang会 ...
- 关于sniff函数的一个小坑
最近在用scapy模块写一个关于WiFi的脚本时用到sniff函数,其中遇到了一个小坑,记录如下: sniff函数是在指定网卡上每次嗅探到一个数据包后然后将它传给prn指定的函数.
- [LeetCode]29 两数相除和一个小坑点
给定两个整数,被除数 dividend 和除数 divisor.将两数相除,要求不使用乘法.除法和 mod 运算符. 返回被除数 dividend 除以除数 divisor 得到的商. 示例 1: 输 ...
- 注意Android里TextView控件的一个小坑,用android:theme来设置样式时动态载入的layout会丢失该样式
注意Android里TextView控件的一个小坑,用android:theme来设置样式时动态载入的layout会丢失该样式 这个坑,必须要注意呀, 比如在用ListView的时候,如果在List_ ...
- mysql url 连接配置的一个小坑。 工作中不会遇到。 学习的时候会
<property name="driverClassName"> <value>com.mysql.jdbc.Driver</value> & ...
- Github作为图床的一个小坑
Github作为图床的一个小坑 前言 听了少铭同学建议把github作为图床,结果遇到了一个小坑,总是显示不出来图片. 问题描述与解决 形如下的链接是显示不出来的: https://github.co ...
- 关于ASPOSE.WORD使用上的一个小问题
最近实习期间负责了公司某个项目的一个功能模块里面的word导出功能,使用的是ASPOSE.WORD类库,但是经常导出时候会遇到图中的问题,大概意思就是两个表格不能跨在一起,调试了好几次还是没发现具体的 ...
随机推荐
- pycharm git 提交使用情况
在IDEA中进行分支切换时,出现如此错误,导致无法正常切换: error: The following untracked working tree files would be overwritte ...
- HTML通过jQuery传值赋值
网页传值很常见,如果通过动态网页传值,我们很容易实现.但是如果静态网页传值,这个就要找资料,方法或者询问大牛们了.这个原来还真的没有做过.今天一同事需要做这个类似的功能,应该是昨天了.本来是昨天写的, ...
- C++进阶3.字节对齐 联合
C++进阶3.字节对齐 联合 20131011 多益和金山笔试 知识漏洞 20131011 前言: 今天下午是多益网络的笔试,整体感觉还好,但是找到很多的知识漏洞.一直笔试到6:00,然后紧张的从会生 ...
- ZooKeeper和Dubbo
前言 Dubbo是阿里开源的一个分布式服务框架,但是阿里内部用的却是HSF(High-speed Service Framework).下面看看怎么使用吧. Zookeeper Dubbo是个RPC调 ...
- New Concept English three (22)
34w 54 Some plays are so successful that they run for years on end. In many ways, this is unfortunat ...
- C# 给窗体添加皮肤 - SkinEngine的应用
C# 给窗体添加皮肤 - SkinEngine的应用 C#中利用 IrisSkin2.dll 所提供的控件 SkinEngine 来为窗体添加皮肤.这种方法最简单 具体步骤: .添加控件SkinE ...
- 【转】DirectUI 资源提取器
转自 http://www.cnblogs.com/Alberl/p/3378413.html 二.DirectUI 资源提取器 由于不能用传统工具,那么怎么办呢?可能有很多网友都知道QQ ...
- MySQL 不开启slave如何完成异地复制
1,分批次通过远程的binlog来进行数据加载 业务新需求,线上数据库数据拉到本次,但是不允许开启slave服务,不建立直接外网的数据库账号,也不能打通数据库对外网的网络,所以我们测试环境无法通过普通 ...
- 特征金字塔网络 FPN
一. 提出背景 论文:Feature Pyramid Networks for Object Detection [点击下载] 在传统的图像处理方法中,金字塔是比较常用的一种手段,像 SIFT 基于 ...
- Postfix邮件黑名单和白名单
本文主要介绍如何用Postfix添加域名黑名单和白名单,用以处理垃圾邮件. 1.修改postfix主配置文件,增加限制语句 vim /etc/postfix/main.cf # 文末添加一行,限制往本 ...