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

前言

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

1、闭包 defer

闭包(匿名函数)github

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);
}

咱们看一下结果:golang

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
4ui

 2、Map

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

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

3、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 
}  

 

感谢阅读,欢迎提供建议

相关文章
相关标签/搜索