一、數組
1.什么是數組?
1.數組是一系列同一類型數據的集合
2.數組中包含的每個數據被稱為數組元素
3.一個數組中包含的元素個數成為數組長度
4.數組的長度是固定的
5.一個數組可以由零個或者多個元素組成
2.數組的申明
var arr [10]int //10個元素的整型數組 var ptrs [5]*float64 //5個元素的指針數組,每個指針都指向float64類型 var points [8]struct{ x, y int } //8個元素的結構體類型 var arry [2][3]int //2*3的二維整型數組 a := [3]int{1, 2, 3} // 長度為3的數組 b := [5]int{1, 2, 3} //長度為10,前三個元素為1、2、3,其它默認為0 c := [...]int{4, 5, 6} //長度3的方式,Go自動計算長度 r := [...]int{9: 6} //長度為10,最后一個元素的值為6,其它默認為0 arr2 := [2][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}}//二維數組
在Go語言中,數組長度在定義后就不可更改,在聲明時長度可以為一個常量或者一個常量表達式。
3.數組的初始化
//申明數組 var a [5]byte //長度為5的數組,每個元素為一個字節 var d [2][3]int //二維數組 //初始化數組 a = {'1','2','3'} d = {{1,2,3},{4,5,6}}
a := [3]byte{'1', '2', '3'} //聲明並初始化一個長度為3的byte數組 a := [...]byte{'1', '2', '3'} //可以省略長度而采用`...`的方式,Go會自動根據元素個數來計算長度 d := [2][3]int{[3]int{1,2,3},[3]int{4,5,6}} d := [2][3]int{{1,2,3},{4,5,6}} //如果內部的元素和外部的一樣,那么上面的聲明可以簡化,直接忽略內部的 類型
4.數組元素訪問
1.可以使用數組下標來訪問數組中的元素
2.數組下標從0開始
3.len(arr)-1則表示最后一個元素的下標
package main import ( "fmt" ) func main() { var result int arr := [...]int{1, 2, 3, 4, 5} len := len(arr) //len獲取數組長度 fmt.Println("修改前:", arr) arr[0] = 100 //下標訪問數組元素 result = arr[3] //取出下標為3的元素並賦值 fmt.Println("修改后:", arr) fmt.Println("數組長度:", len) fmt.Println("方位下標為三的元素:",result) } //運行結果 //修改前: [1 2 3 4 5] //修改后: [100 2 3 4 5] //數組長度: 5 //方位下標為三的元素: 4
package main import( "fmt" ) func main(){ arr := [...]int {9: 1} fmt.Println(arr) fmt.Println(len(arr)) } //運行結果 //[0 0 0 0 0 0 0 0 0 1] //10
package main import( "fmt" ) func main(){ arr := [5]int {1, 2, 3, 4, 5} for i := 0; i < len(arr); i++{ fmt.Printf("arr[%d]=%d\n", i, arr[i]) } } //運行結果 //arr[0]=1 //arr[1]=2 //arr[2]=3 //arr[3]=4 //arr[4]=5
package main import( "fmt" ) func main(){ arr := [5]int {1, 2, 3, 4, 5} for i, v := range(arr) { fmt.Printf("arr[%d]=%d\n", i, v) } } //運行結果 //arr[0]=1 //arr[1]=2 //arr[2]=3 //arr[3]=4 //arr[4]=5
5.數組的傳遞
1.數組作為函數的參數仍然是值傳遞(值傳遞是復制數組給函數,傳遞后數組跟原數組沒有關系)
2.雖然可以使用數組的指針來代替,但是改變不了數組長度。(可以改變數組內的值,但是不能改變數組的長度)
package main import "fmt" func main() { arr1 := [5]int{1, 2, 3, 4, 5} fmt.Println("交換前arry1= " ,arr1) swap(arr1 ) fmt.Println("交換后arry1= " ,arr1) } func swap(a [5]int) { arr3 := a fmt.Println("值傳遞交換前arr3= ",arr3) c := arr3[0] arr3[0] = arr3[4] arr3[4] = c fmt.Println("值傳遞交換后arr3= ",arr3) } //運行結果 //交換前arry1= [1 2 3 4 5] //值傳遞交換前arr3= [1 2 3 4 5] //值傳遞交換后arr3= [5 2 3 4 1] //交換后arry1= [1 2 3 4 5]
package main import "fmt" func main() { arr1 := [5]int{1, 2, 3, 4, 5} fmt.Println("交換前arry1= " ,arr1) swap_pointer(&arr1 ) fmt.Println("交換后arry1= " ,arr1) } func swap_pointer(a *[5]int) { var arr3 *[5]int arr3 = a fmt.Println("指針傳遞交換前arr3= ",arr3) c := arr3[0] arr3[0] = arr3[4] arr3[4] = c fmt.Println("指針傳遞交換后arr3= ",arr3) } //運行結果 //交換前arry1= [1 2 3 4 5] //指針傳遞交換前arr3= &[1 2 3 4 5] //指針傳遞交換后arr3= &[5 2 3 4 1] //交換后arry1= [5 2 3 4 1]
6.數組的比較
1.如果數組元素的類型是可比較的,那么這個數組也是可的比較
2.只有數組的所有元素都相等數組才是相等的。
3.由於長度也是數組類型的一部分,所以長度不同的數組是不等的。
4.數組可遍歷、可修改,是否可比較,由數組元素決定。
5.%T用於顯示一個值對應的數據類型。
7.數組的局限性
1.數組的長度在定義之后無法修改。
2.數組是值類型,每次傳遞都將產生一份副本。
3.顯然這無法滿足開發者的某些需求。
二、切片(slice)
1.什么是切片?
1.切片(Slice)是一個擁有相同類型元素的可變長度的序列。
2.Go語言切片的內部結構包含地址、大小和容量。
3.切片一般用於快速地操作一塊數據集合。
4.slice 總是指向底層的一個 array。
5.slice本身不是數組,slice 是一個指向 array的指針。
切片結構和內存分布示意圖

2. 從數組或者一個切片中生成一個切片
slice [開始位置:結束位置:容量]
a. slice 表示目標切片對象
b. 開始位置對應目標切片對象的索引
c. 結束位置對應目標切片的結束索引
package main import "fmt" func main() { var a = [5]int{1,2,3} var c []int c = a[1:4:5] fmt.Println("c的長度為:%d",len(c)) fmt.Println("c的容量為:%d",cap(c)) fmt.Printf("c的類型:%T",c) } //運行結果 //c的長度為:%d 3 //c的容量為:%d 4 //c的類型:[]int
從數組或切片生成新的切片擁有如下特性
a.取出的元素數量為:結束位置-開始位置
b.取出元素不包含結束位置對應的索引,切片最后一個元素使用 slice[len(slice)] 獲取
c.當缺省開始位置時,表示從連續區域開頭到結束位置
d.當缺省結束位置時,表示從開始位置到整個連續區域末尾
e.兩者同時缺省時,與切片本身等效
f.兩者同時為0時,等效於空切片,一般用於切片復位
(ps:根據索引位置取切片 slice 元素值時,取值范圍是(0~len(slice)-1),超界會報運行時錯誤。生成切片時,結束位置可以填寫 len(slice) 但不會報錯。)
3.直接申明新切片
每一種類型都可以擁有其切片類型,表示多個類型元素的連續集合。
var name []T //name 表示切片類型的變量名。 //T 表示切片類型對應的元素類型。
package main import "fmt" func main() { // 聲明字符串切片 var strList []string // 聲明整型切片 strList = []string{"asa","esd"} var numList []int // 聲明一個空切片 numListEmpty := []int{1,2,3} // 輸出3個切片 fmt.Println(strList, numList, numListEmpty) // 輸出3個切片大小 fmt.Println(len(strList), len(numList), len(numListEmpty)) // 切片判定空的結果 fmt.Println(strList == nil) fmt.Println(numList == nil) fmt.Println(numListEmpty == nil) } //運行結果 //[asa esd] [] [1 2 3] //2 0 3 //false //true //false
ps: 1. 切片是動態結構,只能與nil判定相等,不能互相判等。
2. 聲明新的切片后,可以使用append() 函數來添加元素。
4.使用 make() 函數構造切片
語法:
make( []T, size, cap )
T:切片的元素類型
size:就是為這個類型分配多少個元素
cap:預分配的元素數量,這個值設定后不影響 size,只是能提前分配空間,降低多次分配空間造成的性能問題
package main import "fmt" func main() { a := make([]int, 2) b := make([]int, 2, 10) fmt.Println(a, b) fmt.Println(len(a), len(b)) } //運行結果 //[0 0] [0 0] //2 2
1. a 和 b 均是預分配 2 個元素的切片,只是 b 的內部存儲空間已經分配了 10 個,但實際使用了 2 個元素。
2. 容量不會影響當前的元素個數,因此 a 和 b 取 len 都是 2。
(ps:使用 make() 函數生成的切片一定發生了內存分配操作。但給定開始與結束位置(包括切片復位)的切片只是將新的切片結構指向已經分配好的內存區域,設定開始與結束位置,不會發生內存分配操作。)
5、使用append向切片追加單個元素
1.append() 可以為切片動態添加元素。
2.每個切片會指向一片內存空間,這片空間能容納一定數量的元素。
3.當空間不能容納足夠多的元素時,切片就會進行“擴容”。
4.“擴容”操作往往發生在 append() 函數調用時。
package main import "fmt" func main() { //聲明一個整型切片。 var numbers []int for i := 0; i < 10; i++ { //循環向 numbers 切片添加10個數。 numbers = append(numbers, i) //打印輸出切片的長度、容量和指針變化。使用 len() 函數查看切片擁有的元素個數,使用 cap() 函數查看切片的容量情況 fmt.Printf("len: %d cap: %d pointer: %p\n", len(numbers), cap(numbers), numbers) } } //運行結果 //len: 1 cap: 1 pointer: 0xc00001c060 //len: 2 cap: 2 pointer: 0xc00001c090 //len: 3 cap: 4 pointer: 0xc000016120 //len: 4 cap: 4 pointer: 0xc000016120 //len: 5 cap: 8 pointer: 0xc00001e180 //len: 6 cap: 8 pointer: 0xc00001e180 //len: 7 cap: 8 pointer: 0xc00001e180 //len: 8 cap: 8 pointer: 0xc00001e180 //len: 9 cap: 16 pointer: 0xc000088000 //len: 10 cap: 16 pointer: 0xc000088000
a.len() 函數並不等於 cap。
b.當元素個數超過cap()的數量時,切片會進行擴容
c.擴容后切片的內存地址發生改變
d.但是切片的名稱沒有發生改變。
6、使用append向切片中追加多個元素/其他切片
package main import "fmt" func main() { var car []string // 添加1個元素 car = append(car, "OldDriver") // 添加多個元素 car = append(car, "Ice", "Sniper", "Monk") // 添加切片 team := []string{"Pig", "Flyingcake", "Chicken"} car = append(car, team...) fmt.Println(car) } //運行結果 //[OldDriver Ice Sniper Monk Pig Flyingcake Chicken]
在team后面加上了...,表示將 team 整個添加到 car 的后面。
