1、 for循环中使用短变量声明初始值

案例1:

type Data struct {
d *int
} func main() {
list := make([]Data, 0)
for i := 0; i < 10; i++ {
list = append(list, Data{ d: &i})
}
for _, item := range list {
fmt.Printf("%d ",*item.d)
}
fmt.Println()
}

预期输出:

0  1  2  3  4  5  6  7  8  9

实际输出:

10  10  10  10  10  10  10  10  10  10

原因是在Go中,变量声明之后,在同一作用域中,对于同一变量名,后续的声明是不会分配新的变量(即没有新的地址空间),所以这里的 i 的内存地址始终不变。因此每次变量 i 指向的地址值 最终为10。对于该问题,使用一个新的变量存储,然后再想slice中append临时变量的地址地址即可,如下:

for i := 0; i < 10; i++ {
temp := i
list = append(list, Data{ d: &temp})
}

案例2:

for-range中初始化使用短变量

func main() {
sl := []int{1,2,3,4,5,6,7,8,9}
list := make([]*int, len(sl)) for i, v := range sl{
list[i] = &v
} fmt.Println(list)
}

此处list中元素的地址都是指向0xc00012a000,其原因与上述一致。解决方法也是使用一个临时变量存储即可

2、go并发的坑 -闭包陷阱

案例1:

package main

import (
"fmt"
"sync"
"time"
) func main() {
wg := sync.WaitGroup{}
wg.Add(2)
for i := 0; i < 2; i++ {
go func() {
prefix := fmt.Sprintf("%d", i+1)
for c := 'A'; c <= 'A'; c++ {
fmt.Printf("%s:%c\n", prefix, c)
time.Sleep(time.Millisecond)
}
wg.Done()
}()
}
fmt.Println("Card")
wg.Wait() }

输出如下:

案例2:

package main

import (
"fmt"
"runtime"
"time"
) func main() {
var a [10]int
for i := 0; i < 10; i++ {
go func() {
for {
a[i]++
runtime.Gosched()
}
}()
}
time.Sleep(time.Millisecond)
fmt.Println("a", a)
}

案例3:

func main() {
var wg sync.WaitGroup sl := []int{1,2,3,4,5,6,7,8,9} for i, v := range sl{
go func() {
defer wg.Done()
fmt.Println(i, v) }()
wg.Add(1)
} wg.Wait()
}

实际输出如下:

8 9
8 9
8 9
8 9
8 9
8 9
8 9
8 9
8 9

这里输出的结果,i, v都是一样的,其原理和上面一样,也是由于变量只会在第一次声明时初始化。这里解决办法是直接使用闭包函数传参,将i,v作为参数传递进去(会进行拷贝),从而达到预期效果,改进代码如下:

go func(i, v int) {  // 注意这里的参数变化
defer wg.Done()
fmt.Println(i, v)
}(i, v)

3、defer的坑 -闭包陷阱

案例1

package main

import "fmt"

func main() {
for i := 3; i > 0; i-- {
defer func() {
fmt.Print(i, " ")
}()
}
}

问题解析:这里是极度容易踩坑的地方,由于defer这里调用的func没有参数,等执行的时候,i已经为0(按3 2 1逆序,最后一个i=1时,i--的结果最后是0),所以这里输出3个0 。

如果还不理解:

package main

import "fmt"

func main() {
for i := 3; i > 1; i-- { // 循环满足条件的是 3 2,
defer func() { // 因为func 没有参数,defer运行最后i--即 2-- 结果为 1
fmt.Print(i, " ") // 循环2次 结果均为 1
}()
}
}//输出 1 1 

go常见的坑的更多相关文章

  1. Golang开发者常见的坑

    Golang开发者常见的坑 目录 [−] 初级 开大括号不能放在单独的一行 未使用的变量 未使用的Imports 简式的变量声明仅可以在函数内部使用 使用简式声明重复声明变量 偶然的变量隐藏Accid ...

  2. 纯Socket(BIO)长链接编程的常见的坑和填坑套路

    本文章纯属个人经验总结,伪代码也是写文章的时候顺便白板编码的,可能有逻辑问题,请帮忙指正,谢谢. Internet(全球互联网)是无数台机器基于TCP/IP协议族相互通信产生的.TCP/IP协议族分了 ...

  3. 学习笔记之C/C++指针使用常见的坑

    https://mp.weixin.qq.com/s/kEHQjmhNtSmV3MgHzw6YeQ 避免内存泄露 不再用到的内存没有释放,就叫做内存泄露 在C/C++中,通过动态内存分配函数(如mal ...

  4. 详讲H5、WebApp项目中常见的坑以及注意事项

    首先我们中会有一些常用的meta标签,如下: <!--防止手机中网页放大和缩小--> <meta name="viewport" content="wi ...

  5. Android中常见的坑有哪些?

    对于安卓开发入门级程序猿而言,由于不熟悉代码.工具等等,掉进一些坑中是难免的,今天小编在网上看到一位大神总结的Android开发中比较常见的坑及其原因和解决办法,赶脚还不错,分享出来,给大家提个醒. ...

  6. Android使用WebView开发常见的坑

    原文链接:http://mp.weixin.qq.com/s?__biz=MzAwODE1NTI2MQ==&tempkey=uP3a%2BOgIN7vPbLfJp3BTCl2KabYi1%2F ...

  7. Go语言常见的坑

    目录 1. 可变参数是空接口类型 2. 数组是值传递 3.map遍历是顺序不固定 4. 返回值被屏蔽 5.recover必须在defer函数中运行 6. main函数提前退出 7.通过Sleep来回避 ...

  8. 【常见踩坑】USB调试安装失败(Installation failed with message INSTALL_CANCELED_BY_USER)

    一.写在前面 最近一直在忙活着项目重构,忙活了一个多月(那是天天加班,不分昼夜呀,ps:这不是我司要求的哈),终于把沉积了三四年的老项目给重构了,目前在测试阶段,也总算有了点闲时来跟大家分享分享一些问 ...

  9. Mybatis通过注解方式实现批量插入数据库 及 常见的坑

    原文地址:http://f0rb.iteye.com/blog/1207384 MyBatis中通过xml文件配置数据库批量操作的文章很多,比如这篇http://www.cnblogs.com/xcc ...

  10. Spring,SpringMvc配置常见的坑,注解的使用注意事项,applicationContext.xml和spring.mvc.xml配置注意事项,spring中的事务失效,事务不回滚原因

    1.Spring中的applicationContext.xml配置错误导致的异常 异常信息: org.apache.ibatis.binding.BindingException: Invalid ...

随机推荐

  1. 零基础入门 Java 后端开发,有哪些值得看的视频?

    目前网络上充满了大量的 Java 视频教程,然而内容却鱼龙混杂,为了防止小伙伴们踩坑,一枫结合自己的学习经验,向大家推荐一些不错的学习资源. 作为一名非科班转码选手,可以说,我是在哔哩哔哩上的研究生! ...

  2. 中国风?古典系?AI中文绘图创作尝鲜!⛵

    作者:韩信子@ShowMeAI 深度学习实战系列:https://www.showmeai.tech/tutorials/42 本文地址:https://www.showmeai.tech/artic ...

  3. python之实现文件的读写

    很早之前做自动化测试,并没有将测试数据与数据库关联,而是直接通过json.ymal.excel等文件管理的.那么怎么用python读写文件呢? 在操作文件前,都需要打开文件,打开文件用内置函数open ...

  4. week_2

    Andrew Ng 机器学习笔记 ---by OrangeStar Week_2 1.Multiple Features 更有效的线性回归形式 此时,h函数已经不是二阶了. \[ X = \begin ...

  5. Prometheus高可用架构介绍

    Prometheus作为新生代的开源监控系统,慢慢成为了云原生体系的监控事实标准,也证明了其设计得到业界认可.但在多集群,大集群等场景下,Prometheus由于没有分片能力和多集群支持,还有Prom ...

  6. vlc qt player 播放器开发实例

    (一)VLC-Qt下载 官网地址:https://vlc-qt.tano.si/ Github 地址:https://github.com/vlc-qt 示例地址:https://github.com ...

  7. Hugging Face - 推理(Inference)解决方案

    每天,开发人员和组织都在使用 Hugging Face 平台上托管的模型,将想法变成概念验证(proof-of-concept)的 demo,再将 demo 变成生产级的应用. Transformer ...

  8. WPF中下拉框即可以选择项也可以作为只读文本框使用

    1.需求 当前在开发的系统需要一个这样的控件. (1)可以选择已有的选择项,类似于ComboBox选择: (2)可以通过其他按钮点击,选择一个文件,选择后,把文件路径显示到控件上,并且处于只读状态,行 ...

  9. Python读取大量Excel文件并跨文件批量计算平均值

      本文介绍基于Python语言,实现对多个不同Excel文件进行数据读取与平均值计算的方法.   首先,让我们来看一下具体需求:目前有一个文件夹,其中存放了大量Excel文件:文件名称是每一位同学的 ...

  10. C#零基础小白快速入门

    前言 本文写给想学C#的朋友,目的是以尽快的速度入门 C#好学吗? 对于这个问题,我以前的回答是:好学!但仔细想想,不是这么回事,对于新手来说,C#没有那么好学. 反而学Java还要容易一些,学Jav ...