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 

最新文章

  1. 学习笔记 :DrawText
  2. 编写bat(批处理文件)的优势
  3. 参考__Linux
  4. 用c#实现$.now()(1437813924915)的时间效果
  5. 读书笔记_Effective_C++_条款四十六:需要类型转换时请为模板定义非成员函数
  6. hdu1595 dijkstra+枚举
  7. Java基础-CGLIB动态代理
  8. [Effective JavaScript 笔记] 第1章:让自己习惯javascript小结
  9. XML详解:第一部分
  10. flex+java将数据库里的数据导出到指定目录下excel表里(poi)
  11. JS--事件对象中部份浏览器不兼容方法
  12. 自行架设DNS的操作步骤及相关说明
  13. 关于Javascript&quot;数组&quot;那点事儿
  14. hadoop深入研究:(十八)——Avro schema兼容
  15. svn add后的数据如何取消-svn revert??--zz
  16. C#中大List的内存分配
  17. 我在网站开发中经常用到的几个js函数01
  18. hibernate ——helloWorld程序(XML配置)
  19. 浅谈C++中的友元关系
  20. ubuntu linux 安装分区

热门文章

  1. Django框架:10、Ajax补充说明、多对多三种创建方法、Django内置序列化组件、批量操作数据方法、分页器思路、form组件
  2. AcWing341. 洛谷P1073, NOIP2009 最优贸易
  3. C/C++随堂笔记
  4. Introduction &amp; Directory
  5. 1、Java数据类型
  6. asp前端无法获取后端中select *查询带出来的全部字段
  7. Hadoop详解(04)-Hdfs
  8. A. Greatest Convex【Codeforces Round #842 (Div. 2)】
  9. 企业应用架构研究系列二十五:IdentityServer4 认证服务搭建
  10. 第一个shell