go学习笔记(数组&切片)

数组

数组是存储在一段连续内存中的固定长度的数据类型。数组中的数据类型是一致的可以是内置的类型,也可以是自定义的数据结构类型,由于在内存中是连续的所以很容易计算索引,快速迭代数组中的内容。

  1. 数组的声明和初始化以及使用
var arr1 [5]int //声明一个长度为5的数组,声明后数组的长度不能改变,数组中的值总是用零值存储。
arr2 := [5]int{1,2,3,4,5}// 声明并初始化长度为5的数组,并且数组中的值依次是{1,2,3,4,5}
arr3 := [...]int{1,2,3,4,5} //... 数组的长度由初始化的值决定。
arr4 := [5]int{1:5,2:4} //声明长度为5的数组,初始化数组中下标为1和2的值为5,打印数组{0,5,4,0,0}
arr4[1] = 2 //2赋给数组中下标为2的元素。打印数组{0,5,2,0,0}
arr5 := [5]*int{0:new(int),1:new(int)} //数组中的值是指针。new(int)创建一个空指针,类型是int
var arr6 [5]int
arr6 = arr2 //赋值给arr6后,会拷贝一份数组的副本,两个数组的长度,类型都是一样的。不同长度or类型不能赋值
arr7 := [2][string]{new(string),new(string)}
arr7[0] = "test"
arr7[1] = "test2"
var arr8 [2]*string
arr8 = arr7 //arr8 和arr7指向同样字符串数组。
  1. 数组的底层存储

举个栗子:arr2 := [5]int{1,2,3,4,5}

[0] [1] [2] [3] [4] [5]
1 2 3 4 5 6
[0] [1] [2] [3] [4] [5]
指向下面的test 指针 指针 指针 指针 指针
Test1 Test2 Test3 Test4 Test5 Test6
  1. 多维数组
var arr [2][4]int //声明一个长度为2的二维int数组,分别存储长度为4的一个数组。
arr1[2][4]int := { //声明初始化二维数组
  {1,2,3,4},
  {1,2,3,4}
}
arr1[0][0] = 2 //{{2,2,3,4},{1,2,3,4}}

数组在函数中传递默认是值传递,因此如果传递一个特别大的数组,比如100M的数组,那么在函数调用的时候会完整的拷贝数组,所以开销会很大,应该避免使用大数组进行函数之间的传递。

切片

切片是一种动态的数组,其底层和数组一样分配的是一段连续的内存空间,切片可以自动增长和缩小,切片有长度和容量,长度就是运算的个数,容量就是切片最大可一装多少个元素,在每次对切片增加元素的时候扩容,每次扩容都是一倍的增长,当容量增长大于1000的时候容量的增长因子就会设为1.25,每次增长25%。

  1. 切片的实现

切片是一个很小的对象,包含了3个字段的数据结构,分别是指向数组底层的指针,长度,容量。

指向数组底层的指针 长度3 容量4 整型的切片<br />长度:3,容量:4
\downarrow
[0] [1] [2] [3]
10 15 20 0
  1. 切片的创建和初始化
var slice1 = make([]string, 3) //创建一个字符串类型的切片,长度为3,容量也为3
var slice1 = make([]string, 3, 5) //创建一个字符串类型的切片,长度为3,容量也为5
var slice1 = make([]string, 3, 2) //len larger than cap in make([]string) 不能创建长度小于容量的切片

var slice []int //声明一个切片,不初始化,那么slice的指向数组底层的指针就是一个nil。
var slice = make([]string, "")//声明一个空切片
slice := []int{} //声明并初始化一个空切片,此时数组底层并不分配空间,直到append值进去后才会分配。

slice2 := []string{"chujiu","xiaodong","wangsan"} //创建一个字符串类型切片,长度和容量分别是3
slice3 := []string{99:""} //创建一个长度和容量都是100的切片,并初始化弟100个元素为空字符

//数组的声明初实话方式,数组需要指定长度。
arr := [...]string{"chujiu","lalala"} 
arr := [2]string{"chujiu","lalala"}
//切片的初始化,不需要指定长度
slice := []string{"chujiu","lalala"}
  1. 切片的使用
slice := []int{1,2,3,4,5}
slice[1] = 1 // 修改索引为1的值, result: [1,1,3,4,5]

/**
 * 创建一个新的切片,长度为2,容量为4。
 * 根据一个切片创建出来的切片第一个元素开始算到原始切片的容量就是新切片的容量。
 * 切片的容量始终是从第一个元素开始算的
 * 如果一个切片的容量=k,长度=l,那么slice[i:j]产生新的切片,切片容量=k-i,长度=j-i。
 * 创建的切片和原切片共享同一个底层数组,两个切片的指针指向同一个底层数组。
 * 如果其中一个切片的值发生了变化,那么另一个切片的值同样会发生变化。
 */
newSlice := slice[1:3]
fmt.Print(newSlice[4]) //error: index out of range [4] with length 2

newSlice := slice[1,6] //error: slice bounds out of range [:6] with capacity 5
var slice  = make([]int, 2, 3) //创建一个长度为2,容量为3的切片
slice[1] = 2
newSlice := slice[0:3] // result: [0,2,0]

举个栗子:

slice := []int{1,2,3,4,5}
newSlice := slice[1:3] //newSlice = [2,3]
newSlice = append(newSlice, 6) //newSlice = [2,3,6]

底层存储:

image-20200102120819232.png

但是当底层数组容量不足的时候,运行append追加元素,newSlice则会产生一个新的底层数组,数组的容量是原来的2倍,这个时候修改新切片的值不会影响原来的切片的值。append会优先使用已有的容量,如果不够了才会扩容,分配一个新的底层数组

slice := []int{1, 2, 3, 4, 5}
newSlice := slice[1:4]
newSlice = append(newSlice, 6)
fmt.Print(newSlice, "\n", slice, "\n") // newSlice = [2,3,4,6] slice = [1,2,3,4,6]

newSlice = append(newSlice, 7)
newSlice[1] = 8 //修改newSlice索引为1的值,不会影响slice,因为此时底层已经是2个数组了。
/**
 * slice = [1,2,3,4,6] 
 * newSlice = [2,8,4,6,7]
 * len(newSlice) = 5
 * cap(newSlice) = 8
 */
fmt.Print(slice , newSlice,  "\n",  len(newSlice), cap(newSlice), "\n") 

<u>写代码的时候会很容易忘记2个切片共享一个底层数组的问题,所以我们可以利用3个索引创建新的切片,使用append函数,让切片进行一次扩容,这样新的切片和原切片就彻底分离了,再修改就不会污染原来的切片。</u>

s := []string{"chu","xiao","wang","li","zhao"}
/**
 * 创建一个新切片,长度为2,容量也为2的新切片,
 * [1:3:3]表示取切片中索引为1到3的元素,不算索引为3的元素到新的切片中。
 * 最后一个3表示容量的限制,限制容量是2个。意思是限制新的切片到s的容量的第3个,当然不算第三个。
 * [i:j:k] 表示长度为j-i,容量为k-i
 */
newS := s[1:3:3]

//append后再修改newS的值就不会影响原来的切片
newS = append(newS, "hahah") // [xiao wang hahah] 长度为3 容量为4
newS[1] = "" //[xiao  hahah] 中间其实是有一个空值,只是打印出来看不见了。

迭代

/**
 * k和v只在当前block中有效。
 * for range迭代是一个值的拷贝,而不是引用数组元素的地址。
 * 每迭代一次都是把当前数组的元素的值拷贝给value,所以value的地址始终是同一个,只是迭代的过程中值不一样。
 * 如果要获取每个元素的地址就不能用&value,而是&s1[k]这样获取
 */
for k, v := range s1 { 
        fmt.Print(k, "--", v, "\n")
}
fmt.Print(k, v) //undefined: v

多维切片

slice := [][]int{{1,2},{1,2,3}} //创建一个多维的切片,和一纬的一样,切片的值指向另一个切片,另一个切片的指针指向底层真正的数组
/**
 * 追加一个值到第一个切片中,result {{1,2,3},{1,2,3}}
 * 对于多维切片的长度总是以外层的切片个数决定。slice的长度为2,容量也是2
 * go中append总是先增长切片,再将新的值赋给第一个外层的切片。
 */
slice = append(slice[0], 3)
var slice1  = make([][]int, 2, 3) // [[],[]] 创建一个长度为2的多维切片,容量为3。

总结

数组在函数之间传递是拷贝传值,如果数组太大影响性能。

切片在函数之间传递只是传递的切片的3个字段结构,(指针,长度,容量),真正存储数据的是底层的数组,所以性能很高。

数组必须指定长度,而切片可以动态扩容。

切片的底层存储数据结构依赖于数组。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容

  • 切片(slice)是 Golang 中一种比较特殊的数据结构,这种数据结构更便于使用和管理数据集合。切片是围绕动态...
    小孩真笨阅读 1,070评论 0 1
  • 数组Go语言中的数组是定长的同一类型数据的集合,数组索引是从0开始的。数组有以下几种创建方式 以下是一些特殊数组 ...
    小杰的快乐时光阅读 1,688评论 0 0
  • 切片(slice)是 Golang 中一种比较特殊的数据结构,这种数据结构更便于使用和管理数据集合。切片是围绕动态...
    51reboot阅读 28,649评论 2 10
  • 明明有很多事要做,但一点也不想做,每次都是拖到最后一刻,熬夜去完成。 每次都很疲惫,就想进入了一个死循环,生活里除...
    木萧鸣阅读 260评论 0 2
  • 智慧牙,人类进化过程中的遗留物,对人类的摄食与消化已毫无帮助…… 从开始长智慧牙都现在已经有数不清的年头了,基本上...
    溪桥澄月阅读 109评论 0 0