golang关于一些新手不注意会出现的小问题

turnswing · · 2204 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

前言

最近在整理之前写程序,学习时所记录的有道云笔记,发现一些有意思的小点跟大家分享一下。如有错误请大家给指出

一、闭包 defer

闭包(匿名函数)

func test(){ i, n := 1 ,2; defer func(a int){ fmt.Println("defer:", a , n); //n被闭包引用 }(i) //复制i的值 i , n = i+1,n+2; fmt.Println(i , n); }

我们看一下结果:

2 4
defer: 1 4

为什么会这样?是因为闭包复制的是原对象指针出现了延迟引用现象 (加上defer的延迟调用,正好可以解释上面程序的延迟引用现象)。我们在使用闭包的时候要注意这个问题,同样在for 循环中 也会出现类似现象。

感谢“”小强”,增加一个闭包的例子,期望能给大家带来更多的理解

func b(){	i := []int{1,2,3,4}	for _,n := range i {	go func(){	fmt.Println(n); // n 被闭包引用,引用n的内存地址 // 协程G 实际上执行的是匿名函数对象 FuncVal { func_address, closure_var_pointer ... }	}();	fmt.Println(n);	}	time.Sleep(1*time.Second); } 

  

 程序有一定的不确定性 ,但是输出结果反映了内存引用现象

1
2
3
4
4
4
4
4

 二、Map

前一段时间在论坛看到一个问题

type Data struct{ AABB [2]float64 } var m map[string]Data = make(map[string]Data,1) m["xxx"] = Data{} m["xxx"].AABB[0]=1.0 m["xxx"].AABB[1]=2.0
#以上代码go build 通不过,错误提示cannot assign to m["xxx"].AABB[0]

这是一个网友给出的答案

type Data struct{ AABB [2]float64 } m := make(map[string]*Data,1) m["xxxx"] = Data{} m["xxxx"].AABB[0] = 1.0 m["xxxx"].AABB[1] = 2.0 #这样写就对了,你的 m["xxxx"] 返回的是值,不是一个可取地址的变量

这个网友的答案可以编译成功,但是不可取,他犯了很多新手都容易出现的问题

why?Golang中的map元素属性被设计为只读的,并不期望被修改,并且从 map 中取回的是一个value也是临时复制品。并且map是一个hash 结构,当hash扩容时,键值的存储位置就会发生改变。如果这个时候我们对 m["xxxx"].AABB[0] = 1.0 修改,不知道指针会发什么。大家有兴趣可以看看Go Hashmap内存布局和实现

 如果我们想修改最好这样

type Data struct{ AABB [2]float64 } m := make(map[string]*Data,1) m["xxxx"] = &Data{} d := m["xxxx"] d.AABB[0] = 1.0 d.AABB[1] = 2.0 m["xxxx"] = d 

三、nil

先看一段代码,当然这种场景不常见,但是能让我们更好的理解nil

func t(){	var i *int = nil;	var n interface{} = i;	fmt.Println(n==nil); //false }

 

可能很多小伙伴都会有疑问都是nil 为啥会不相等。我们先分别看一下pointer,interface的结构体和当pointer,interface为nil时的结构

uintptr type interfaceStruct struct {   v *_value // 实际值   t *_type // 实际值的类型信息 } uintptr(0) == nil type interfaceStruct struct {   v:uintptr(0)   t:uintptr(0) } == nil 

  

由此我们可以看出nil其实就是指针 interface的零值

这时候我们在来解释为啥为flase就很容易了

func t(){	var i *int = nil; // (*int)nil	var n interface{} = i; // interace{}((*int)nil)	fmt.Println(n==nil); // type interfaceStruct struct {                  // v: uintptr(0),                  // t: (*int)                  // } } 

  

官方文档规定可以为nil的类型还有 slice ,map ,channel ,function 。

可能有些朋友可能会问为啥没有error类型,那是因为error 只是程序预设的接口方法, err nil 也会出现类似的问题,官方有一个文档也给出了解释,传送门

type error interface { Error() string }  

 

感谢阅读,欢迎提供建议

 


有疑问加站长微信联系(非本文作者)

本文来自:博客园

感谢作者:turnswing

查看原文:golang关于一些新手不注意会出现的小问题

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

2204 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传