专栏首页技术面面观Go语言中的数组和切片 len cap append copy

Go语言中的数组和切片 len cap append copy

先来看看Golang中的数组

其实在循环那一节用到过数组,我快速介绍一下。

  • 数组中是固定长度的连续空间(内存区域)
  • 数组中所有元素的类型是一样的
 var a1 [10]int
  
 //初始化数组
 var b1 = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

多维数组

//声明二维数组,只要 任意加中括号,可以声明更多维,相应占用空间指数上指
 var arr [3][3]int
 //赋值
 arr = [3][3]int{
  {1, 2, 3},
  {2, 3, 4},
  {3, 4, 5},
 }

何谓切片?

类比c语言,一个int型数组int a[10],a的类型是int*,也就是整型指针,而c语言中可以使用malloc()动态的分配一段内存区域,c++中可以用new()函数。例如:

int* a = (int *)malloc(10);
int* b = new int(4);

此时,ab的类型也是int*ab此时分配内存的方式类似于go语言中的切片。

Go的数组和切片都是从c语言中延续过来的设计。

有何不同?

var sliceTmp []int

可以看到和c不同的是,go可以声明一个空切片(默认值为nil),然后再增加值的过程中动态的改变切片值大小。

怎么动态增加?

增加的方式只有一种,使用append函数追加。

sliceTmp = append(sliceTmp, 4)
sliceTmp = append(sliceTmp, 5)

每个切片有长度len和容量cap两个概念,长度是我们最熟知的,和数组长度相同,可以直接用来遍历。

for _,v := range slice1{
  fmt.Println(v)
 }

用切糕来对比

每个切片,在声明或扩建时会分配一段连续的空间,称为容量cap,是不可见的;真正在使用的只有一部分连续的空间,称为长度len,是可见的。

每次append时,如果发现cap已经不足以给len使用,就会重新分配原cap两倍的容量,把原切片里已有内容全部迁移过去。

新分配的空间也是连续的,不过不一定直接在原切片内存地址处扩容,也有可能是新的内存地址。

切片的长度与容量,len cap append copy

slice1 := []int{1, 2, 3}

普通切片的声明方式,长度和容量是一致的。

len=3 cap=3 slice=[1 2 3]

当然,控制权在我们手上,我们可以自己控制长度和容量,

 slice1 = make([]int, 3, 5) // 3 是长度 5 是容量

输出

len=3 cap=5 slice=[0 0 0]

尝试使用一般的方式扩容

slice1[len(slice1)] = 4 
//报错 panic: runtime error:
//index out of range [3] with length 3

这种方式是会报错的,虽然容量是 5 ,但是数组长度是3,这里是以长度为准,而不是容量,append内部如果超过容量相当于创建了一个新数组,每个新数组都是定长的,只不过外部是切片。

尝试扩容

slice1 = append(slice1, 4)

输出,可以发现len扩容了!

len=4 cap=5 slice=[0 0 0 4]

让我们连续扩容,让容量超过5

slice1 = append(slice1, 5)
slice1 = append(slice1, 6) // 到这里长度超过了容量,容量自动翻倍为 5*2

输出

len=6 cap=10 slice=[0 0 0 4 5 6]

上面的过程,我 用自己的代码模拟一遍

// 上面容量自动翻倍的过程可以看作和下面一致
 slice1 = make([]int, 3, 5) // 3 是长度 5 是容量
 slice1 = append(slice1, 4)
 slice1 = append(slice1, 5)

// 长度不变,容量自动翻倍为 5*2
 slice2 := make([]int, len(slice1), 
          (cap(slice1))*2)

 // 拷贝 slice1 的内容到 slice2 
  // 注意是后面的拷贝给前面
 copy(slice2, slice1) 
  
 slice2 = append(slice2, 6) 

本文分享自微信公众号 - 编程三分钟(coding3min),作者:放假中的小熊

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-05-05

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 让你的Golang项目在IDE里跑起来(Goland使用入门-GOROOT、GOPATH、src、 pkg、bin...)

    每次新建项目,不熟悉go的项目结构,一般跑都跑不起来,每次都要重新搞一遍,好几回跑项目都会报类似File is invalid的错误

    机智的程序员小熊
  • 三分钟学 Go 语言——range深度解析

    小熊最近两天加班比较严重,要处理的事情很多,但是学习的热情永远不会减少,前面讲述的go语言语法是非常非常简单的,所以没有做深入的剖析,后面会从各种角度解析语法,...

    机智的程序员小熊
  • 00后小哥告诉你,何谓桶排序?

    我们经常在学校学习阶段听到木桶原理这个词,意思就是说这个木桶所能装载的水的量是由最短的那个木板决定的

    机智的程序员小熊
  • 数据库血海一片 浪潮为何非要趟这浑水?

    其实从前两年开始,坊间就不断传出浪潮要进军数据库市场,于去年底月浪潮宣布与Tmax共同建立合资公司,浪潮也因此拿到了Tmax中国区的知识产权和经营授权,由此开展...

    人称T客
  • 让代码更有效率的方法

            老大总结的代码级提高代码执行效率需要注意的点,很值得和大家分享一下,在这儿也由衷地感谢下老大的总结和工作中的指导。大多数的点都在项目中验证过,比...

    王亚昌
  • Golang Leetcode 674. Longest Continuous Increasing Subsequence.go

    更多内容请移步我的repo:https://github.com/anakin/golang-leetcode

    anakinsun
  • 构建企业级网络设备自动备份系统 -- Oxidized (ubuntu 20.04 LTS)

    Oxidized 0.28.0 测试环境使用 CentOS 7.6 系统 ,缺点是 CentOS 7 系统集成的软件版本太低。Oxidized 需运行在 rub...

    Kevin song
  • PC微信逆向:两种姿势教你解密数据库文件

    微信的数据库使用的是 sqlite3,数据库文件在C:\Users\XXX\Documents\WeChat Files\微信账号\Msg这个路径下,

    信安之路
  • 为带有多种语言的 Jekyll 博客添加多语言选择

    发布于 2018-03-06 06:47 更新于 2018-09...

    walterlv
  • 极路由4刷OpenWrt(LEDE)

    scp -P 1022 breed-mt7621-hiwifi-hc5962.bin root@192.168.199.1:/tmp

    霡霂

扫码关注云+社区

领取腾讯云代金券