关于golang:Golang-切片和数组总结

9次阅读

共计 2147 个字符,预计需要花费 6 分钟才能阅读完成。

最近起步学习 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-1
s := 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,扭转其中之一另一个不会收到影响

程序后果:

11
10
参考:

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

正文完
 0