Skip to content

Go - array 和 slice #31

@wangpin34

Description

@wangpin34

注:slice 中文翻译做切片,个人以为并不贴切,所以本文不使用切片称呼。

前言

编程语言的学习都绕不开数据类型这个话题,而数组作为支持最广泛的基础数据类型,其定义和使用在各个语言中基本大同小异。从这一点上说,编程语言互相借鉴(抄袭)一点都没有错。但之所以还会有这么多编程语言被发明和使用,是因为他们的应用场景或有所不同。比如偏重于组织复杂业务逻辑的,或者高并发性能的。

golang 中的数组的定义和使用都及其简单,但依然有他特别的地方,值得记录下来,以供查阅和分享。

数组初始化

定义数组只需要给出下面两个要素

  1. 元素类型
  2. 长度或者初始化元素
    比如,创建一个长度为 2 的字符串数组,并赋值:
arr1 := [2]string{}
arr1[0] = "a"
arr1[1] = "b"

或者,初始化同时赋值

arr1 := []string{"a", "b"}

此时,长度值可以省略,数组长度以初始元素个数为准

操作数组

通过下标的方式访问数组元素,这个没什么可说的,java 如此,js 亦如此。

arr1[0]

更新:

arr1[0] = "a1"

数组的长度固定,所以,访问超出限制的下标将会导致 panic 程序中断。

index out of bounds

slice

slice 是对数组的一种高级抽象,底层存储依赖数组。实际项目中,slice 可以用作“可变长”数组。有两种定义 slice 的方法。

通过指定初始下标和结束下标(不包含)选取部分元素,如:

slice1 := arr1[0:1]

使用 make 函数,三个参数分别为初始化数组,长度,容量:

slice2 := make([]string{}, 2, 4)

可以看到,两种定义办法,都少不了一个底层数组。

操作 slice

访问和更新元素的方式和普通数组相同,所不同的是,slice 可以增加长度,这是个很有实际意义的特质。因为很多业务场景下,并不能确定元素的个数。

前面说到 slice 底层存储依然是数组,但数组是定长的,slice 是如何做到可变长的呢?通过下面的小实验可以稍微猜度一下。

playground

func print(s []string) {
  fmt.Printf("len(%d),cap(%d),elements:%s , %p \n", len(s), cap(s), s, s)
}

func main() {
  s := make([]string, 1, 2)
  print(s)
  s[0] = "a"
  print(s)
  s = append(s, "b")
  print(s)
  s = append(s, "c")
  print(s)
}

结果:

len(1),cap(2),elements:[] , 0x40c0e0 
len(1),cap(2),elements:[a] , 0x40c0e0 
len(2),cap(2),elements:[a b] , 0x40c0e0 
len(3),cap(4),elements:[a b c] , 0x442260 

当 cap 达到限制后,append 会返回一个新的 slice(注意新指针地址 0x442260),以及更大的 cap。所以,可以猜想,当 cap 发生变化时,Go 会创建一个新的数组,并将指针指向此数组。

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions