前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go语言之make

Go语言之make

作者头像
灰子学技术
发布2020-06-03 14:58:10
4000
发布2020-06-03 14:58:10
举报
文章被收录于专栏:灰子学技术

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 节点根据参数类型的不同转换成了 OMAKESLICEOMAKEMAPOMAKECHAN 三种不同类型的节点,这些节点会调用不同的运行时函数来初始化相应的数据结构。

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

代码语言:javascript
复制
make(type, len, cap) // len和cap都可以省略掉

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

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

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

代码语言:javascript
复制
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))
}

运行结果:

代码语言:javascript
复制
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起不到限制的作用。

代码语言:javascript
复制
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)
}

执行结果

代码语言:javascript
复制
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/

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-05-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 灰子学技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档