Go语言之make

1.make介绍

     对于make来说,是Go语言之用来分配内存的函数,使用在slice,map,chan这三种数据类型上面。因为这三种数据类型的特殊性,用来分配和初始化这三种数据类型,参考原文:

原文:

It creates slices, maps, and channels only, and it returns an initialized (not zeroed) value of type T (not *T). The reason for the distinction is that these three types represent, under the covers, references to data structures that must be initialized before use. 

https://golang.org/doc/effective_go.html#allocation_make

    

     不过对于这三种数据类型,Go的做法并不相同,在编译期间的类型检查阶段,Go 语言就将代表 make 关键字的 OMAKE 节点根据参数类型的不同转换成了 OMAKESLICEOMAKEMAP 和 OMAKECHAN 三种不同类型的节点,这些节点会调用不同的运行时函数来初始化相应的数据结构。

make的语法结构非常简单,如下所示:

make(type, len, cap) // len和cap都可以省略掉

2. make使用中的一些常见坑

对于make的使用来说,特别是在使用slice和map的时候,差别还是比较大的,并且稍不注意,就会踩坑,下面是本作者实际工作中碰到的2个坑。

1)slice使用make

:slice在make了之后,设置了slice的大小之后,实际上是在slice里面添加了len个空数据,如果在使用append来操作的话,相当于在slice后面添加新的元素,例子如下:

package main


import (
  "fmt"
  "strconv"
)


func main() {
        // 1.slice不带capacity的make
  strs:=make([]string,10)
  fmt.Println("make(t,len),len:",len(strs),"strs:",strs,"cap:",cap(strs))
  strs = append(strs,"hello") // 相当于在10个元素之后追加数据
  fmt.Println("make(t,len),len:",len(strs),"strs:",strs,"cap:",cap(strs))
  
  // 2.带capacity的make
  strs1:=make([]string,10,15)
  fmt.Println("make(t,len),len:",len(strs1),"strs1:",strs1,"cap:",cap(strs1))
  strs1 = append(strs1,"hello")
  fmt.Println("make(t,len),len:",len(strs1),"strs1:",strs1,"cap:",cap(strs1))
  
  // 3.在slice中使用已经分配好的空间的做法
  strs2:=make([]string,10)
  fmt.Println("make(t,len),len:",len(strs2),"strs2:",strs2,"cap:",cap(strs2))
  for i:=0;i<len(strs2);i++ {
    strs2[i] = "Hello"+strconv.Itoa(i)
  }
  fmt.Println("make(t,len),len:",len(strs2),"strs2:",strs2,"cap:",cap(strs2))
}


运行结果:

make(t,len),len: 10 strs: [         ] cap: 10
make(t,len),len: 11 strs: [          hello] cap: 20
make(t,len),len: 10 strs1: [         ] cap: 15
make(t,len),len: 11 strs1: [          hello] cap: 15
make(t,len),len: 10 strs2: [         ] cap: 10
make(t,len),len: 10 strs2: [Hello0 Hello1 Hello2 Hello3 Hello4 Hello5 Hello6 Hello7 Hello8 Hello9] cap: 10

2)map使用make

坑:map在使用make的时候,就算指定了len,也是不起作用的,这个len起不到限制的作用。

package main


import (
  "fmt"
  "strconv"
)


func main() {
        // 1.map不带len的make
        strs:=make(map[int]string)
  fmt.Println("make(t,len),len:",len(strs),"strs:",strs)
  strs[0]="Hello"
  fmt.Println("make(t,len),len:",len(strs),"strs:",strs)
  
  // 2.带len的make
  strs1:=make(map[int]string,3)
  fmt.Println("make(t,len),len:",len(strs1),"strs1:",strs1)
  strs1[0]="Hello"
  fmt.Println("make(t,len),len:",len(strs1),"strs1:",strs1)
  
  // 3.在map中使用,可能会犯的错,len并没有起到作用
  strs2:=make(map[int]string,3)
  fmt.Println("make(t,len),len:",len(strs2),"strs2:",strs2)
  for i:=0;i<len(strs2);i++ {
    strs2[i] = "Hello"+strconv.Itoa(i)
  }
  fmt.Println("make(t,len),len:",len(strs2),"strs2:",strs2)
  
  for i:=0;i<3;i++ {
    strs2[i] = "Hello"+strconv.Itoa(i)
  }
  fmt.Println("make(t,len),len:",len(strs2),"strs2:",strs2)
  
  // 就算使用map的元素超过了make的大小,也没有关系,map看起来这个len没特别的作用
  strs2[3] = "Hello3"
  fmt.Println("make(t,len),len:",len(strs2),"strs2:",strs2)
}


执行结果

make(t,len),len: 0 strs: map[]
make(t,len),len: 1 strs: map[0:Hello]
make(t,len),len: 0 strs1: map[]
make(t,len),len: 1 strs1: map[0:Hello]
make(t,len),len: 0 strs2: map[]
make(t,len),len: 0 strs2: map[]
make(t,len),len: 3 strs2: map[0:Hello0 1:Hello1 2:Hello2]
make(t,len),len: 4 strs2: map[0:Hello0 1:Hello1 2:Hello2 3:Hello3]

参考资料:

https://golang.org/doc/effective_go.html#allocation_make

https://blog.golang.org/maps

https://draveness.me/golang/docs/part2-foundation/ch05-keyword/golang-make-and-new/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值