Go 數組(array) & 切片(slice)


數組

數組是一組固定長度的序列

數組類型

數組的類型不僅和儲存元素的類型有關,還和數組長度有關,不同長度的數組是不同的類型
不同類型的數組不能共用一個函數

func main() {
	var a [10]int
	var b [5]int
	var c [5]int32
	fmt.Printf("type a: %T,\ntype b: %T,\ntype c: %T", a, b, c)
}

儲存數據

由於數組中儲存的是值,所以直接傳入函數中無法改變原來的值,需要傳入地址才能修改原來的值

傳值

示例:

func change(a [5]int){
	fmt.Println("in change, before change", a)
	a[0] = 100
	fmt.Println("in change, after change", a)
}

func toChange() {
	a := [5]int{0, 0, 0, 0, 0}
	fmt.Println("in main, before change", a)
	change(a)
	fmt.Println("in main. after change", a)
}

輸出結果:

in main, before change [0 0 0 0 0]
in change, before change [0 0 0 0 0]
in change, after change [100 0 0 0 0]
in main. after change [0 0 0 0 0]

main 中數組並沒有改變

傳引用

示例:

func change(a *[5]int){
	fmt.Println("in change, before change", *a)
	a[0] = 100
	fmt.Println("in change, after change", *a)
}

func main() {
	a := [5]int{0, 0, 0, 0, 0}
	fmt.Println("in main, before change", a)
	change(&a)
	fmt.Println("in main. after change", a)
}

輸出結果:

in main, before change [0 0 0 0 0]
in change, before change [0 0 0 0 0]
in change, after change [100 0 0 0 0]
in main. after change [100 0 0 0 0]

main 中數組發生改變

數組初始化

在數組未進行初始化時,所有的元素都是默認值

// 標准初始化
var array [5]int = [5]int{1, 2, 3, 4, 5}

// 省略類型,會自動判斷數組長度與元素類型
var array = [5]int{1, 2, 3, 4, 5}

// 省略長度,會自動判斷初始化元素個數來確定長度
var array = [...]int{1, 2, 3, 4, 5}

// 指定索引初始化
var array = [5]int{0: 3, 4: 3}

切片

切片時數組的一個引用,是引用類型
切片長度可變

切片的結構

切片內部儲存的只有指向相應數組對應元素的指針和切片的長度、容量

package main

import "fmt"

func main() {
	var array = [5]int{1, 2, 3, 4, 5}
	var slice = array[2:]
	fmt.Printf("array: %p slice: %p\n", &array[2], slice)
}

輸出結果:

array: 0xc00001a160 slice: 0xc00001a160

切片從 array[2] 開始,所以指向的就是 array[2]

切片定義

var slice[]int

切片初始化

切片初始化的時候可以自己創建一個數組進行初始化,也可以用 make 進行初始化,但是 make 實際上也是創建了一個數組,切片的數據都存在這個數組里,切片改變數組里的值也會改變

// 通過數組初始化
var slice[]int = array[start: end]

// 通過 make 初始化,第一個參數為類型,第二個參數為長度,第三個參數為數組長度,默認等於切片長度
var slice = make([]int, len)
var slice = make([]int, len, cap)

二維切片初始化

二維切片外層直接初始化,但是內層需要循環每個外層切片進行初始化

slice := make([][]int, height)
for i := range slice {
	slice[i] = make([]int, width)
}

append

append 用於在切片后面添加元素

用法

// 切片后添加元素
slice = append(slice, elems)

// 切片后添加切片
// slice... 用來將 slice 展開
slice = append(slice, slice...)	

實現

由於切片是基於數組的,但是數組的長度不可變,所以進行 append 操作時,
如果內存空間不足:切片會新開辟一段內存空間由於存儲新數組,每次開辟都是原來數組長度的兩倍
如果內存空間夠用:切片會使用原來數組的內存,修改數組中原來的元素

開辟空間示例:

func main() {
	var array = [10]int{}
	var slice = array[:]
	fmt.Printf("slice %p len: %d\n", slice, len(slice))
	slice = append(slice, 2)
	fmt.Printf("slice %p len: %d(should change)\n", slice, len(slice))
	slice = append(slice, slice[:len(slice) - 2]...)
	fmt.Printf("slice %p len: %d(should not change)\n", slice, len(slice))
	slice = append(slice, 1)
	fmt.Printf("slice %p len: %d(should change)\n", slice, len(slice))
}

輸出結果:

slice 0xc00001e050 len: 10
slice 0xc0000140a0 len: 11(should change)
slice 0xc0000140a0 len: 20(should not change)
slice 0xc00008c000 len: 21(should change)

初始數組長度為 10,
append 1 個元素之后,長度為 11,由於超過數組最大長度,所以需要開辟新的內存空間,長度為 20,切片指向的地址發生改變
append 9 個元素之后,長度為 20,由於沒有超過數組最大長度,所以指向不變
append 1 個元素之后,長度為 21,由於超過數組最大長度,所以需要開辟新的內存空間,長度為 40,切片指向的地址發生改變

修改數組示例:

func main() {
	var array = [10]int{8: 1}
	var slice = array[: 8]
	fmt.Printf("slice %p len: %d\n", slice, len(slice))
	fmt.Printf("array: %v\n", array)
	slice = append(slice, 2)
	fmt.Printf("slice %p len: %d(should not change)\n", slice, len(slice))
	fmt.Printf("array: %v\n", array)
	slice = append(slice, 2)
	fmt.Printf("slice %p len: %d(should not change)\n", slice, len(slice))
	fmt.Printf("array: %v\n", array)
	slice = append(slice, 2)
	fmt.Printf("slice %p len: %d(should change)\n", slice, len(slice))
	fmt.Printf("array: %v\n", array)
}

輸出結果:

slice 0xc00001e050 len: 8
array: [0 0 0 0 0 0 0 0 1 0]
slice 0xc00001e050 len: 9(should not change)
array: [0 0 0 0 0 0 0 0 2 0]
slice 0xc00001e050 len: 10(should not change)
array: [0 0 0 0 0 0 0 0 2 2]
slice 0xc0000140a0 len: 11(should change)
array: [0 0 0 0 0 0 0 0 2 2]

初始數組長度為 10,但是切片切了前 8 個元素
append 的元素未超過數組本身的長度時,會直接修改數組中原來的元素,如果超過了,則開辟新的內存

copy

copy 用來復制切片
如果被復制的切片元素不足,多余部分不變
如果被復制的切片元素超出目標切片長度(與容量無關),則忽略超出部分
用法:

// 切片 dst 變為 切片 scr 的復制
copy(dst []Type, src []Type)

示例:

func main(){
	a := []int{1, 2, 3, 4, 5}
	b := make([]int, 3, 4)
	fmt.Printf("b: %v, a: %v\n", b, a)
	copy(b, a)
	fmt.Printf("b: %v, cap: %d, prt: %p\n", b, cap(b), b)
	b = append(b, 1)
	fmt.Printf("b: %v, cap: %d, prt: %p\n", b, cap(b), b)
	copy(b, a)
	fmt.Printf("b: %v, a: %v\n", b, a)
}

輸出結果:

b: [0 0 0], a: [1 2 3 4 5]
b: [1 2 3], cap: 4, prt: 0xc000018140
b: [1 2 3 1], cap: 4, prt: 0xc000018140
b: [1 2 3 4], a: [1 2 3 4 5]

string

字符串 (string) 就是 bytes 組成的不可變的集合
關於字符串類型 <- 點擊查看


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM