数组和切片

数组

数组是一个单一元素类型,长度固定的元素序列,其在内存中的位置是连续的,如下

var x [5]int
x[4] = 100

strings一样,数组的下标是从0开始计数的, 由于数组的长度是固定的,对数组的元素进行删减操作将会比较繁琐,因此比较常用的是对数组进行更高层次的封装的slice

初始化

数组的创建需要指明数组的长度以及对应存储元素的类型,一个数组一旦被声明,那么其长度和元素类型将会是不可在变更的

如果你需要在数组中存储更多的元素,那么你需要创建一个新的长度的数组,并将旧数组的元素复制过去

  1. 声明一个数组并设置其元素为初始值

    var array [5]int
    
  2. 使用字面量声明一个数组

    array := [5]int{1,2,34,5,6}
    
  3. 利用推导声明一个数组,数组的容量取决于初始化的时候,给定元素的数量

    array := [...]int{1,2,54,3,4}
    
  4. 声明并初始化特定元素的值

    array := [5]int{1:10, 2:20}
    
  5. 指针数组

    array := *int{0:new(int), 1:new(int)}
    *array[0] = 10
    *array[1] = 20
    fmt.Println(array) // [0xc420014118 0xc420014130 <nil> <nil> <nil>]
    

    此时打印出来的将会是一个存放了元素地址的数组

在Go中,一个数组就是一个值,因此可以对其进行赋值操作,变量的名称代表整个数组,一个相同类型的数组可以进行相互赋值(相同的类型指的是:长度相同,元素类型相同):

    var array1 [5]string
    array2 := [5]string{"a", "b", "c", "d", "e"}
    array1 = array2
    fmt.Println(array1)

以上将两个数组进行赋值操作,赋值之后,不同数组内的相同位置的元素代表的是不同地址中的值,但是对于指针数组来说,进行赋值操作之后,两个数组内的相同位置的元素指向的是相同位置中的值

    var array1 [3]*string
    array2 := [3]*string{new(string), new(string), new(string)}
    *array2[0] = "a"
    *array2[1] = "b"
    *array2[2] = "c"
    array1 = array2
    fmt.Println(array1) //[0xc42007c1b0 0xc42007c1c0 0xc42007c1d0]
    fmt.Println(array2) //[0xc42007c1b0 0xc42007c1c0 0xc42007c1d0]
多维数组
声明
var array [4][2]int

//使用字面量声明并初始化多维数组
array := [4][2]int{{10,12}, {20,21}, {30,31}, {40, 41}}

//声明并初始化特殊位置的值的数组
array := [4][2]int{1:{20,21}, 3:{40,41}}
array1 := [4][2]int{1:{0:20}, 3:{1:41}}

与一维数组一样,也可以通过下标来获取元素,相同类型的元素可以进行相互赋值

数组作为值进行传递

将数组作为值在函数中进行传递,是一个非常耗费内存对性能影响非常大的一个操作,当使用变量在函数中进行传递的时候,是将整个变量的值进行拷贝,然后再进行传递,比如:

var array [1e6]int
foo(array)
func foo(array [1e6]int){
  //TODO
}

每一次foo函数进行调用的时候,8M的内存将会被占用,当传递的值是一个数组的时候,所有的数据将会被复制一份,因此我们需要使用指针来解决这个问题

var array [1e6]int

foo(&array)

fun foo(array *[1e6]int){
  //TODO
}

切片

切片是对数组的分割,与数组的共同点是可被索引以及含有长度,不同于数组的是,其长度是可变的

var x []float64

切片的声明和数组的声明唯一的不同就是,切片的声明在括号中没有长度的限制,如上就声明了一个长度为0的切片,这个时候是不能对切片进行任何的操作

如果需要创建一个切片,应该使用内置的make函数:

x := make([]float, 5)

如上创建了一个与底层数组(长度为5)相关联的切片,切片总是和数组进行相关联,因此切片的长度不能比其底层的数组长,只能小于或等于其底层数组长度

当然,make函数还接受第三个参数

x := make([]float64, 5, 10)

其中,10代表的是其底层数组的容量,因此这里引出了切片的两个重要的属性:长度和容量。

  • 长度,切片所包含的元素的数量,可以使用len(s)来进行查看
  • 容量,切片的第一个元素对应的底层数组位置的开始,到数组末尾的元素的元素数量,使用cap(s)进行查看

另外一种创建切片的方法是使用[low:high]表达式:

arr := [5]float64{1,2,3,4,5}
x := arr[0:5]

需要注意的是,该表达式是一个左开右闭的,只会包含左边的区间,更为便利的是我们可以省略low或者high,或者两者都进行省略

对于索引操作,Go内置了两个与切片相关的操作函数appendcopy函数

append

该函数添加元素到切片的末尾

  • 如果切片的容量足够,那么元素将会被直接添加到切片末尾,切片长度改变,容量不变
  • 如果切片容量不足,将会创建一个新的数组,切片中的所有元素将会被复制到新数组中,新添加的元素继续增加到新数组的末尾,并且返回一个新的切片
copy
copy(dst, src []Type)

src中的元素复制到dst中,如果两个切片的长度不一样,那么两者之中较短的那一个将会被当做接受元素的目标

func main () {
  slice1 := []int{1,2,3}
  slice2 := make([]int, 2)
  copy(slice2,slice1)
  fmt.Println(slice1, slice2)
}

如上所示,本意是将slice1中的值复制到slice2中,但是slice2的容量为2,小于slice1中的元素的长度,所以只有讲slice1复制到slice2

切片的一个典型应用是表示一个子元素的一个列表,这样就可以通过下标快速检索一个元素

results matching ""

    No results matching ""