一.數組 數組的定義:相同類型的數據集合 go語言中數組的索引從0開始 沒有賦值的數值型數組,預設值為0 數組一旦被創建,它的大小就是不可改變的 (1)聲明數組與列印 var 變數名 [大小]變數類型 //數組的聲明 var nums [4]int //數組的賦值 nums[0] = 1 nums[ ...
一.數組
- 數組的定義:相同類型的數據集合
- go語言中數組的索引從0開始
- 沒有賦值的數值型數組,預設值為0
- 數組一旦被創建,它的大小就是不可改變的
(1)聲明數組與列印
var 變數名 [大小]變數類型
//數組的聲明
var nums [4]int
//數組的賦值
nums[0] = 1
nums[1] = 2
nums[2] = 3
nums[3] = 4
/***************數組的列印*************/
fmt.Printf("%T\n", nums) //列印數組的類型:[4]int
fmt.Println(nums[3]) //列印單個數組的值:4
fmt.Println("長度:", len(nums)) //列印數組的長度:4
fmt.Println("容量:", cap(nums)) //列印數組的容量:4
(2)數組的初始化
在go語言中,數組有多種初始化方式。
- 常量初始化定義數組
- 快速的定義數組
- 定義不確定長度的數組
- 給指定下標進行賦值操作
//1、常量的初始化定義數組
var arrs1 = [5]int{1, 2, 3, 4, 5}
//2、快速定義數組
arrs2 := [5]int{6, 7, 8, 9, 10}
//3、定義不確定長度的數組
arrs3 := [...]string{"hello", "xuexiangban", "kuangshenshuo"}
//4、給指定下標進行賦值操作
arrs4 := [5]int{1: 100, 3: 200}//給下標為1賦值為100,下標為3賦值為200
(3)數組的遍歷
- for迴圈遍歷
//1、for迴圈遍曆數組
arr1 := [5]int{1, 2, 3, 4, 5} //創建數組
for i := 0; i < len(arr1); i++ {
fmt.Println(arr1[i])
}
/*輸出結果:
1
2
3
4
5
*/
- for-range遍歷方式
//2、forage迴圈遍曆數組
for index, value := range arr1 { //index下標,value對應的值
fmt.Println(index, value)
}
/*輸出結果:
0 1
1 2
2 3
3 4
4 5
*/
(4)數組是值傳遞類型
- 在go語言中,數組被看作是值傳遞類型,因此數組之間可以直接相互賦值
arr1 := [3]int{1, 2, 3} //創建數組1:整型
arr2 := [2]string{"hello", "xuexiangban"} //創建數組2:字元型
arr3 := arr1 //創建數組3直接被賦值數組1
fmt.Println(arr1, arr3) //列印結果:[1 2 3] [1 2 3]
arr3 = [3]int{4, 5, 6} //重新賦值
fmt.Println(arr1, arr3) //[1 2 3] [4 5 6]
(5)多維數組
- go語言支持多維數組,以下為常用的多維數組聲明方式
var 變數名[SIZE1][SIZE2]...[SIZEN]變數類型
- 多維數組定義示例:
arr := [3][4]int{
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
}
- 多維數組使用示例
//forage迴圈輸出
for _, i := range arr {
fmt.Println(i) //列印外層
fmt.Println("=========") //列印內層
for _, i2 := range i {
fmt.Println(i2)
}
}
/*列印結果:
[1 2 3 4]
=========
1
2
3
4
[5 6 7 8]
=========
5
6
7
8
[9 10 11 12]
=========
9
10
11
12
*/
二.切片
Go語言切片是對數組的抽象
go語言數組的長度是不可改變的,切片的長度是不固定的,可以追加元素,在追加時可能使切片的容量增大
切片是一種方便、靈活且強大的包裝器,切片本身沒有任何數據,他們只是對現有數組的引用
切片與數組相比,不需要設定長度,在[]中不用設定值,相對來說比較自由
(1)定義創建切片
切片與數組在定義時不同,可以不用指定長度容量
//1、定義一個切片,裡面不添加數據,列印輸出
s1 := []int{}
fmt.Println(s1) //輸出結果:[]
//2、定義切片向裡面添加數據,列印輸出類型
s2 := []int{1, 2, 3}
fmt.Println(s2) //輸出結果:[1 2 3]
fmt.Printf("%T", s2) //輸出結果[]int
補充:長度(length)和容量(cap)區別
-
長度(length)指切片中當前包含的元素個數。使用內置函數
len()
可以獲取切片的長度。 -
容量(capacity)指分配給切片的底層數組中可用於存儲元素的空間大小。容量至少等於切片長度,但可能會更大以容納未來的增長。使用內置函數
cap()
可以獲取切片的容量。 -
在創建切片的時候,可以只指定長度也可以同時指定長度和容量。當只指定長度時,切片的容量與長度相等。當同時指定長度和容量時,切片的容量可以大於長度。
(2)make函數創建切片
make函數創建切片,可以指定切片的長度和容量
make([]T,length,capactity) //類型,長度,容量
- 使用示例
//1、通過make函數來創建切片
s1 := make([]int, 5, 10) //長度:5,容量為10
//2、給切片裡面的元素進行賦值
s1[0] = 100
//3、列印輸出長度,容量
fmt.Println(s1)
fmt.Println("長度:", len(s1))
fmt.Println("容量:", cap(s1))
(3)切片擴容append
- 註意:追加數據超過容量後,容量只會2倍擴容,地址會發生改變
//1、創建一個切片s1
s1 := make([]int, 2, 4)
fmt.Println("追加數據前的長度和容量:", len(s1), cap(s1))
//2、s1通過append追加數據
s1 = append(s1, 1, 2, 3, 4) //追加數據,不是添加數據
fmt.Println(s1)
fmt.Println("追加數據後的長度和容量:", len(s1), cap(s1))
// 3、創建一個s2,將s2中數據追加到s1
s2 := make([]int, 3, 3)
s2 = []int{1, 2, 3}
s1 = append(s1, s2...) //將s2裡面的數據追加到s1
fmt.Println(s1)
(4)在已有數組上創建切片
從已有的數組上,直接創建切片,該切片的底層數組就是當前的數組,長度是從start到end切到的數據量,但是容量從start到數組的末尾。
從數組上創建的切片,地址與數組是一樣的,因此修改數組或切片的某個值,對應的數組/切片的值也會改變
slice := arr[start:end]
//定義數組和其切片
arr := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
s1 := arr[:5] //切片從1-5 [1 2 3 4 5]
s2 := arr[4:8] //[5 6 7 8]
s3 := arr[5:] //[6 7 8 9 10]
s4 := arr[:] //[1 2 3 4 5 6 7 8 9 10]
fmt.Println(s1) //[1 2 3 4 5]
fmt.Println(s2) //[5 6 7 8]
fmt.Println(s3) //[6 7 8 9 10]
fmt.Println(s4) //[1 2 3 4 5 6 7 8 9 10]
//修改數組的某個值
arr[0] = 100 //將數組元素值進行更換
fmt.Println(arr) //[100 2 3 4 5 6 7 8 9 10]
fmt.Println(s1) //[100 2 3 4 5 6 7 8 9 10]
//修改切片的某個值
s1[1] = 100
fmt.Println(arr) //[100 100 3 4 5 6 7 8 9 10]
fmt.Println(s1) //[100 100 3 4 5]
//查看數組和對應切片的地址
fmt.Printf("%p\n", s1) //0xc0000ac0f0
fmt.Printf("%p\n", &arr) //0xc0000ac0f0
(5)切片是引用類型
- 與數組不同,數組是值傳遞類型,而切片是引用類型
- 數組之間可以直接賦值,改變其中一個數組的值,另一個數組的值不會發生改變
- 切片之間若直接賦值,則改變其中一個切片的值,另一個切片的值同樣發生改變
s1 := []int{1, 2, 3, 4, 5}
s2 := s1
s2[0] = 100
fmt.Println(s1, s2) //切片2里元素髮生變化,切片1也會跟隨著變化
fmt.Printf("%p\t%p", s1, s2) //說明切片的copy指向的是地址
(6)copy深拷貝與淺拷貝
- 深拷貝:拷貝的是數據本身
- 淺拷貝:拷貝的是數據的地址,會導致多個變數指向同一塊記憶體
- 引用類型的數據,預設都是淺拷貝,如切片,集合
- 可以用copy強制實現深拷貝
實現切片的深拷貝
//1、通過for迴圈實現切片的深拷貝
s1 := []int{1, 2, 3, 4}
s2 := make([]int, 0, 0)
for i := 0; i < len(s1); i++ {
s2 = append(s2, s1[i])
}
fmt.Println(s1, s2)
//2、通過copy操作實現深拷貝
s3 := []int{5, 6, 7, 8}
fmt.Println(s1, s3)
copy(s3, s1) //(接收者,傳遞者) 將s1 copy 給s3
fmt.Println(s1, s3)