Go 切片的 append 操作总结

Xavier · · 160 次点击 · · 开始浏览    

预备

  • 切片是对其底层数组的某一段的引用。
  • 切片有 lencap 两个属性,代表切片的引用长度和切片的容量(从切片的引用起点位置到其底层数组最末端的长度。因为其底层数组的长度是固定的,这也就是意味着容量是指切片可引用的最大宽度)。

append 函数

slice2 := append(slice1, 23, 15)

以上对切片 slice1 进行 append 操作。该操作遵循以下原则:

  1. append 函数对一个切片 slice1 进行追加操作,并返回另一个长度为 len(slice1) + 追加个数 的切片,原切片不被改动,两个切片所指向的底层数组可能是同一个也可能不是,取决于第二条:
  2. slice1 是对其底层数组的一段引用,若 append 追加完之后没有突破 slice1 的容量,则实际上追加的数据改变了其底层数组对应的值,并且 append 函数返回对底层数组新的引用(切片);若 append 追加的数据量突破了 slice1 的最大容量(底层数组长度固定,无法增加长度赋予新值),则 Go 会在内存中申请新的数组(数组内的值为追加操作之后的值),并返回对新数组的引用(切片)。

示例

// 声明并初始化长度为 5 的整型数组 [0 0 0 0 0]
var arr [5]int

// slice1 和 slice2 是对 arr 第 2 个元素到第 4 个元素的引用
slice1 := arr[1:4] // slice1: [0 0 0]
slice2 := arr[1:4] // slice2: [0 0 0]

// 对切片的修改会反映到底层数组
slice1[0] = 1 // slice1:[1 0 0] slice2:[1 0 0] arr:[0 1 0 0 0]
// 对底层数组的修改同样会反映到指向它的切片
arr[2] = 2 // slice1:[1 2 0] slice2:[1 2 0] arr:[0 1 2 0 0]

// 因为对 slice1 的追加没有突破其底层数组的长度,所以返回的切片还是指向原来的底层数组
slice3 := append(slice1, 4) // slice1:[1 2 0] slice2:[1 2 0] slice3:[1 2 0 4] arr:[0 1 2 0 4]
slice3[2] = 3 // slice1:[1 2 3] slice2:[1 2 3] slice3:[1 2 3 4] arr:[0 1 2 3 4]

// 如果对切片的追加突破了底层数组的长度,则会分配一个新的数组,返回指向新数组的切片
slice3 = append(slice3, 5) // slice1:[1 2 3] slice2:[1 2 3] slice3:[1 2 3 4 5] arr:[0 1 2 3 4]
// slice3 的底层数组已经改变,对它的操作不会影响到 slice1 slice2 和 arr
slice3[0] = 6 // slice1:[1 2 3] slice2:[1 2 3] slice3:[6 2 3 4 5] arr:[0 1 2 3 4]

惯用方式

slice1 = append(slice1, 5, 6)

因为 append 操作的切片变量的类型和返回的切片的类型相同,所以一般将返回值再赋予给原变量。这样被操作的切片变量在操作之后:

  1. 变为对原底层数组新的一段长度的引用,或:
  2. 变为对新数组的引用,原底层数组若无其他地方引用,内存将会被回收。

本文来自:Segmentfault

感谢作者:Xavier

查看原文:Go 切片的 append 操作总结

入群交流(和以上内容无关):Go中文网 QQ 交流群:798786647 或加微信入微信群:274768166 备注:入群;关注公众号:Go语言中文网

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