最近起步学习golang,总结一下golang中切片和数组的关系和不同


1. 数组:

Go语言的数组不同于C语言或者其余语言的数组,C语言的数组变量是指向数组第一个元素的指针;而Go语言的数组是一个值,Go语言中的数组是值类型,一个数组变量就示意着整个数组,意味着Go语言的数组在传递的时候,传递的是原数组的拷贝。你能够了解为Go语言的数组是一种有序的struct
在golang中,数组的特点如下:

    1. 数组为值类型,换言之用数组给变量赋值,是将数组中所有元素拷贝一份
    2. 数组作为函数参数传递为值传递,而不是指针
    3. 数组的长度不可变,即不可进行扩容和缩容



数组的初始化:

//初始长度为5的数组[5] int {1,2,3,4,5}//用...代替初始长度,其长度是依据初始化时指定的元素个数决定的,本例中为5[...] int {1,2,3,4,5}//在初始化元素中能够指定特定下标的起始值,未指定的用0填充//本例中数组为:[0,0,1,0,3][...] int {2:1,4:3}


2. 切片:

数组的长度不可扭转,在特定场景中这样的汇合就不太实用,Go中提供了一种灵便,性能强悍的内置类型Slices切片(“动静数组"),与数组相比切片的长度是不固定的,能够追加元素,在追加时可能使切片的容量增大。切片中有两个概念:一是len长度,二是cap容量,长度是指曾经被赋过值的最大下标+1,可通过内置函数len()取得。容量是指切片目前可包容的最多元素个数,可通过内置函数cap()取得。切片是援用类型,因而在当传递切片时将援用同一指针,批改值将会影响其余的对象,然而这种状况也有一个例外,详见上面扩容局部。

其构造如下:


其数据结构分为3个局部:
    1. 地址指针:记录slice首个元素的地址
    2. 长度:以后slice中存了多少个数据
    3. 容量,以后slice中一共能够存多少数据(当容量有余的时候,会触发扩容机制)



切片的初始化:

//留神中括号中不能够有值,否则初始化的后果为数组s := [] int {1,2,3 }// : 的应用s := arr[:] //arr的全副元素s := arr[startIndex:endIndex] //arr的startIndex到endIndex-1s := arr[startIndex:] //缺省endIndex时将示意始终到arr的最初一个元素s := arr[:endIndex] //缺省startIndex时将示意从arr的第一个元素开始s1 := s[startIndex:endIndex] //也能够用切片初始化切片// 通过内置函数make()初始化切片s,[]int 标识为其元素类型为int的切片s := make([]int,len,cap)

切片的援用机制

如下图

当对slice或者array用冒号进行切片的时候,切片的长度会依据:左右的值进行自行运算,而容量为切片起始点到原数组/切片的完结完结点。

因为是援用类型,子切片值的扭转也会影响到原数组/切片的值

import (    "fmt")func main(){    arr := [4]int{10, 20, 30, 40}    slice := arr[0:2]    slice[0] = 1    // 在触发扩容之前调用append,也会影响原数组的值    slice = append(slice, 99)    fmt.Println(slice)    fmt.Println(arr)}

程序后果:

[ 1 20 99 ][ 1 20 99 40 ]

切片的扩容机制
slice这种数据结构便于应用和治理数据汇合,能够了解为是一种“动静数组”,slice也是围绕动静数组的概念来构建的。既然是动静数组,那么slice是如何扩容的呢?

请记住以下两条规定:

  • 如果切片的容量小于1024个元素,那么扩容的时候slice的cap就翻番,乘以2;一旦元素个数超过1024个元素,增长因子就变成1.25,即每次减少原来容量的四分之一。
  • 如果扩容之后,还没有涉及原数组的容量,那么,切片中的指针指向的地位,就还是原数组,如果扩容之后,超过了原数组的容量,那么,Go就会开拓一块新的内存,把原来的值拷贝过去,这种状况丝毫不会影响到原数组。

晓得了一下规定,请看上面程序,试问输入后果:

import (    "fmt")func main(){    arr := [4]int{10, 20, 30, 40}    slice := arr[0:2]    testSlice1 := slice    testSlice2 := append(append(append(slice, 1),2),3)    slice[0] = 11      fmt.Println(testSlice1[0])    fmt.Println(testSlice2[0])}

因为append了3次而slice中的cap=4,则会触发扩容,因而testSlice2和slice并不是同一个slice,扭转其中之一另一个不会收到影响

程序后果:

1110
参考:
https://blog.csdn.net/belalds/article/details/80076739
https://i6448038.github.io/2018/08/11/array-and-slice-principle/
http://www.topgoer.com/