前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Golang常见的坑笔记

Golang常见的坑笔记

作者头像
solate
发布2019-07-19 17:43:14
4220
发布2019-07-19 17:43:14
举报
文章被收录于专栏:solate 杂货铺

挑战A.I.,赢百万奖金......了解更多详情>>>

Golang 介绍及踩坑系列之三

Golang奇葩点(坑2)

笔记

List的遍历删除

因为是指针所以要先将指针指到下一个元素再删。

代码语言:javascript
复制
错误写法(简洁,漂亮,但是。。。):
for e := l.Front(); e != nil; e = e.Next() {
	l.Remove(e)
}

正确写法
var next *Element
for e := l.Front(); e != nil; e = next {
	next = e.Next()
	l.Remove(e)
}


// 看看具体实现代码(container/list.go)
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
}

时间问题

Format 的时候 时间必须是 2006-01-02 15:04:05 ,奇葩时间。

代码语言:javascript
复制
原因:
这里写死了(time/format.go)
const (
	ANSIC       = "Mon Jan _2 15:04:05 2006"
	UnixDate    = "Mon Jan _2 15:04:05 MST 2006"
	RubyDate    = "Mon Jan 02 15:04:05 -0700 2006"
	RFC822      = "02 Jan 06 15:04 MST"
	RFC3339     = "2006-01-02T15:04:05Z07:00"
	……
)

range

代码语言:javascript
复制
values := []string{"a", "b", "c"}
for _, v := range values {
	go func() {
		fmt.Println(v)
	}()
}
time.Sleep(2*time.Second)
fmt.Println("end")
	    
输出三个c,而不是顺序的a, b, c

//查找错误
values := []string{"a", "b", "c"}
for _, v := range values {   //(1)
	go func() {    //(2)
		fmt.Println(v)   //隐式用v的地址传递
	}()
}
(1)复用了临时变量,只有一个临时变量的空间
(2) 只是goroutine放到调度队列,不是立刻运行,还要排队先,等排到自己的时候,黄花菜已经凉了


解决
for _, v := range values {
	go func(u string) {
		fmt.Println(u)
	}(v)  //明确值复制,作为栈变量
}

类似的
list := make(map[int]*Link)
for _, lnk := range linktree {
       list[lnk.Code] = &lnk
}

解决
list := make(map[int]*Link)
for _, lnk := range linktree {
        var lnk = linktree
       list[lnk.Code] = &lnk 
}

Channel的唤醒时序

当多个channel都处于就绪状态时,激活的channel是随机的

A Tour of Go: A select blocks until one of its cases can run, then it executes that case. It chooses one at random if multiple are ready

切勿想当然的认为先来后到

queue

Golang没有直接的queue

可以预期queue长度的情况下用channel

无法预期长度是用list当作队列用

也可以根据实际情况,将list作为channel的二级队列(sometimes you may need it)

解决方案:

  1. 需要严格顺序处理的都放入一个channel
  2. 设计系统时需要仔细考虑时序的影响,特别是并发环境下

避免大对象拷贝

1.如果map的value较大,通常应该使用指针来存储,以避免性能问题,类似的还有channel,slice等

2.避免[]byte和string的反复来回转换

一个简单的池

代码语言:javascript
复制
func (p *ConnectionPool) InitPool(size int, f FactoryMethod) {
	p.conn = make(chan interface{}, size)
	for i := 0; i < size; i++ {
		p.conn <-  f()
	}
	p.size = size
}

func (p *ConnectionPool) Get() interface{} {
	return <-p.conn
}

func (p *ConnectionPool) Put(conn interface{}) {
	p.conn <- conn
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 笔记
    • List的遍历删除
      • 时间问题
        • range
          • Channel的唤醒时序
            • queue
              • 避免大对象拷贝
                • 一个简单的池
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档