golang那些事儿|数组和切片slice

memo012 · · 409 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

# 目录 - 数组 - 数组概念 - 数组的初始化 - 切片 - slice概念 - slice创建 - slice追加 - slice拼接问题 - slice作为函数参数 - slice的扩容 - 数组和切片slice异同 - 闲聊 - 欢迎加入我的公众号【迈莫coding】 一起pk大厂 # 数组 ## 数组概念 Go语言数组中每个元素都是按照索引来访问的,索引从0到数组长度减一。Go语言中len()函数可以返回数组中的元素个数。 ## 数组的初始化 - 关键字 var 创建数组 ```go package main import "fmt" func main() { var a [3]int // 三个整数型数组 fmt.Println(a) var b = [...]int{6, 7, 8} // 不声明长度 fmt.Println(b) } ``` **结果** ```go [0 0 0] [6 7 8] ``` - 自动初始化 ```go package main import "fmt" func main() { a := [4]int{2, 0, 2, 1} fmt.Println(a) // [2 0 2 1] b := [...]int{2, 0, 2, 1} // 不声明长度 fmt.Println(b) // [2 0 2 1] c := [...]int{3:-1} // 指定索引位置值 fmt.Println(c) } ``` **结果** ```go [2 0 2 1] [2 0 2 1] [0 0 0 -1] ``` # 切片slice ## slice概念 slice是一个结构体,它本身并非动态数组或数组指针。它内部通过指针引用底层数组,设定相关属性将数据读写操作限定在指定区域内。它包含三个成员:len,cap,array,分别表示切片的长度,切片的容量,切片的底层数组的地址。 ## slice创建 这里说一个比较难懂的切片创建及其原理 ```go package main import "fmt" func main() { x := [...]int{10, 30, 20, 50, 80, 90, 100} fmt.Println(x[2:4:6]) } ``` **属性示意图:** ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210101174615712.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMDY2MDY2,size_16,color_FFFFFF,t_70#pic_center) 由图可知,x[2:4:6]表示的切片含义:slice的长度为2,容量为4的切片。 **计算公式:** - **len:** high - low,对应示例为(4 - 2 = 2) - **cap:** max - low,对应示例为(6 - 2 = 4) ## slice追加 ```go package main import "fmt" func main() { s := make([]int, 5) s = append(s, 1, 2, 3) fmt.Println(s) } ``` **结果** ```go [0 0 0 0 0 1 2 3] // make初始化默认为0 ``` ## slice拼接问题 ```go package main import "fmt" func main() { a := []int{1, 2, 3} b := []int{4, 5, 6} a = append(a, b...) fmt.Println(a) } ``` **注意** 两个slice进行拼接时,记住要将第二个参数后面加上 ... ,否则会编译失败。 **结果** ```go [1 2 3 4 5 6] ``` ## slice作为函数参数 在go语言中,函数参数传递只有值传递,没有引用传递。 所以当slice作为函数参数传递时,他也是传递的是原切片的副本。如果直接传slice的话,实参不会被调用函数中的操作而改变;若传递的是slice指针的话,实参是会被影响的。 值得注意的是,不管是指针传递还是值传递,如果改变来slice底层数组中的值, 那么会影响到实参slice中的底层数据。 来一起看个例子: ```go package main import "fmt" func copys(a []int) { // v只是一个副本,不能改变s中元素的值 /* for _, v := range a { v++ } */ for i, _ := range a{ a[i] += 1 } } func main() { s := []int{1, 2, 3} copys(s) fmt.Println(s) } ``` **结果** ```go [2 3 4] ``` ## slice的扩容 当调用append函数向切片尾部(slice[len])添加数据时,如超出cap限制,则会为新切片对象重新分配数组。 ```go package main import "fmt" func main() { s := make([]int, 0, 100) s1 := s[:2:4] s2 := append(s1, 1, 2, 3, 4, 5, 6) fmt.Printf("s1: %p: %v\n", &s1[0], s1) fmt.Printf("s2: %p: %v\n", &s2[0], s2) fmt.Printf("s data: %v\n", s[:10]) fmt.Printf("s1 cap: %d, s2 cap: %d\n", cap(s1), cap(s2)) } ``` **结果** ```go s1: 0xc000102000: [0 0] s2: 0xc00001a040: [0 0 1 2 3 4 5 6] // 数组地址不同,确认新分配 s data: [0 0 0 0 0 0 0 0 0 0] // append 并未向愿数组写入部分数组 s1 cap: 4, s2 cap: 8 // 新数组是新cap 的2倍 ``` **注意** - 是超过切片cap限制,而非底层数组长度限制,因为cap可小于数组长度。 - 当原slice容量小于1024时,新slice容量是原slice容量的2倍;原slice容量大于1024时,新slice容量大于等于原容量的2倍或1.25倍。 # 数组和切片slice异同 | | 数组 |切片slice | |--|--|--| | 长度 | 初始化指定长度 | 长度动态 不固定 | | 创建方式 | | make创建| # 闲聊 - 读完文章,自己是不是和数组/slice的cp率又提高了 - 我是迈莫,欢迎大家和我交流 > 原创不易,觉得文章写得不错的小伙伴,点个赞👍 鼓励一下吧~ # 欢迎加入我的公众号【迈莫coding】 一起pk大厂 - 迈莫coding欢迎客官的到来 ![在这里插入图片描述](https://img-blog.csdnimg.cn/2021010117492223.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMDY2MDY2,size_16,color_FFFFFF,t_70#pic_center)

有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

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