数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 常规声明
var a [3]int
a[0] = 1
a[2] = 3

fmt.Println(a) // 输出 [1 0 3] ,没设置索引对应的值,默认数据类型的零值

// 简短声明,由编译器计算数组长度
b := [...]string{1:"golang"}

fmt.Println(a) // [ golang_array] 其中0下标对应的string零值,也就是 “” 空字符串

// 简短定义多个元素数据,由编译器计算长度
// 这里需要注意,数组的长度11,也就是数组索引是连续性的,如果定义了下标为10的索引为-1,那0-9下标的索引对应定义数据类型的零值
c := [...]int{10: -1}

fmt.Printf("%v --- %d\n",c,len(c)) // [0 0 0 0 0 0 0 0 0 0 -1] -- 11

数组类型比较

不同长度长度数组的是不同的数据类型

1
2
3
4
5
6
7
8
9
10
11
a := [2]int{1,2}

b := [2]int{1,3}

c := [3]int{1,2,3}

d := [...]int{1,2}

fmt.Printf("%T - %T - %t\n",a,b, a == b) // [2]int - [2]int - false
fmt.Printf("%T - %T - %t\n",a,c, a == c) // 编译器报错:Invalid operation: a == c (mismatched types [2]int and [3]int)
fmt.Printf("%T - %T - %t\n",a,d, a == d) // [2]int - [2]int - true

既然长度不同那么就无法比较,无法类型转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 大家应该知道[]byte 类型和字符串类型是可以互相转换的
b := []byte("x")

s := string(b)

// 上面是可以相互转换的,但是[n]byte 和 字符串是无法相互转换的,因为他们类型不匹配,[]type是切片,[n]int是数组,这也是切片和数组的区别

sign := sha256.Sum256(b) // 返回[32]byte,一个byte=8字节,正好256字节

fmt.Println(string(sign)) // 编译器报错:Cannot convert an expression of the type '[Size]byte' to the type 'string'

// 以16进制输出
fmt.Printf("%x\n",sign) // 2d711642b726b04401627ca9fbac32f5c8530fb1903cc4db02258717921a4881

数组与切片的区别

切片 Slice 定义切片 s := []类型 {}

数组 array 定义数组 a := [n]类型{}

从上面的例子可以看出,数组和切片 定义的方式是不同的,其实也能体现数切片和数组的区别,数组是有固定长度,在声明它的时候就必须给定,并且在之后不会再改变。
而切片类型的值是可变长的。而切片的类型字面量中只有其元素的类型,而没有其长度。切片的长度可以自动地随着其中元素数量的增长而增长,但不会随着元素数量的减少而减少。在每一个切片的底层数据结构中,会包含指向底层数组的指针,而切片就是对底层数组的引用,故而切片类型属于引用类型。

切片扩容

1
2
3
4
5
a := []int{}
for i := 0; i < 16; i++ {
a = append(a, i)
fmt.Print(cap(a), " ") // 1 2 4 4 8 8 8 8 16 16 16 16 16 16 16 16
}

根据切片的元素类型、当前切片以及新切片所需的最小容量(即新切片的长度)进行扩容,返回一个至少具有指定容量的新切片,并将旧切片中的数据拷贝过去。

如果新切片所需的最小容量大于当前切片容量的两倍,那么就直接用新切片所需的最小容量
如果新切片所需的最小容量小于等于当前切片的容量的两倍

如果当前切片的容量小于 1024 ,则直接把当前切片的容量翻倍作为新切片的容量
如果当前切片的容量大于等于 1024 ,则每次递增切片容量的 1/4 倍,直到大于新切片所需的最小容量为止。