Go中,陣列是值型別
var hens [7]float64
hens[0] = 3.0
hens[1] = 3.0
hens[2] = 3.0
hens[3] = 3.0
hens[4] = 3.0
totalWeight := 0.0
for i := 0; i < len(hens); i++ {
totalWeight += hens[i]
}
avgWeight := fmt.Sprintf("%.2f", totalWeight/float64(len(hens)))
fmt.Printf("total =%v,avg=%v", totalWeight, avgWeight)
var 陣列名 [陣列大小]資料型別
var class [50]int
var class [3]int = [...]int{1,2,3}
class[0]=1
class[1]=2
當我們定義完陣列後,其實陣列的各個元素有預設值
- 陣列的地址可以通過陣列名來獲取 &intArr
- 陣列的地址就是首位元素的地址
- 陣列的各個元素的地址間隔是依據陣列的型別決定 比如int64->8 int32->4
var intArr [3]int
fmt.Println(intArr)
//[0 0 0]
fmt.Println(&intArr[0])
//0xc000010360
var intArr [3]int
intArr[0] = 10
intArr[1] = 20
intArr[2] = 20
fmt.Printf("intArr的地址=%p intArr[0] 地址%p intArr[1] 地址%p intArr[2] 地址%p", &intArr, &intArr[0], &intArr[1], &intArr[2])
//intArr的地址=0xc000010360 intArr[0] 地址0xc000010360 intArr[1] 地址0xc000010368 intArr[2] 地址0xc000010370
陣列名[下標]
var arr [5]float64
for i := 0; i < len(arr); i++ {
fmt.Printf("請輸入第%d個元素的值\n", i+1)
fmt.Scanln(&arr[i])
}
for i := 0; i < len(arr); i++ {
fmt.Printf("arr[%d]=%v", i, arr[i])
}
var numarr01 [3]int = [3]int{1, 2, 3}
fmt.Println("numarr01=", numarr01)
var numarr02 = [3]int{1, 2, 3}
fmt.Println("numarr02=", numarr02)
var numarr03 = [...]int{8, 9, 10}
fmt.Println("numarr03=", numarr03)
var numarr04 = [...]int{1: 800, 2: 129, 3: 10}
fmt.Println("numarr03=", numarr04)
//型別推導
strArr := [...]string{1: "tom", 2: "jack", 3: "zjm"}
fmt.Println("strArr=", strArr)
//numarr01= [1 2 3]
//numarr02= [1 2 3]
//numarr03= [8 9 10]
//numarr03= [0 800 129 10]
//strArr= [ tom jack zjm]
一般用for或者for–range
heros := [...]string{"zjm", "whq", "xgd"}
for i, v := range heros {
fmt.Printf("i=%v v=%v\n", i, v)
fmt.Printf("heros[%d]=%v\n", i, heros[i])
}
for _, v := range heros {
fmt.Printf("元素的值%v\n", v)
}
使用注意-217
- 陣列是多個相同型別資料的組合,一個陣列一旦什麼了,其長度是固定的,不能動態改變
- Var arr []int arr就是一個切片
- 陣列中的元素可以是任何資料型別,包括值型別和引用型別,但是不能混用
- 陣列建立後,沒有賦值,有預設值 (string :‘’ bool:false 數值型:0)
- 陣列的下標必須在指定範圍內使用,否則報panic:陣列越界
- Go的陣列屬值型別,在預設情況下是值傳遞,因此會進行值拷貝,陣列間不會相互影響
- 如果下在其他函式中,去修改原來的陣列,可以使用引用傳遞(指標方式)
- 長度是陣列型別的一部分,在傳遞函式引數時,需要考慮陣列的長度
var arr [3]int
arr[0] = 1
arr[1] = 2
arr[2] = 3.1
arr[3] = 4
var arr1 [3]float32
var arr2 [3]string
var arr3 [3]bool
fmt.Printf("arr1=%v arr2=%v arr3=%v", arr1, arr2, arr3)
//arr1=[0 0 0] arr2=[ ] arr3=[false false false]
//Go的陣列屬值型別,在預設情況下是值傳遞,因此會進行值拷貝,陣列間不會相互影響
注意是值拷貝,所以呢,這個是在棧裡新建一個陣列
arr := [3]int{11, 22, 33}
test(arr)
fmt.Println(arr)
func test(arr [3]int) {
arr[0] = 88
fmt.Println("test中的arr:", arr)
}
test中的arr: [88 22 33]
[11 22 33]
要改的話,需要用的是指標,改變地址引用
arr := [3]int{11, 22, 33}
test01(arr)
test02(&arr) //傳地址
fmt.Println("arr:", arr)
func test01(arr [3]int) { //go中陣列的長度是型別的一部分 [3]int
arr[0] = 88
fmt.Println("test01中的arr:", arr)
}
func test02(arr *[3]int) {
(*arr)[0] = 88 //指標獲取到地址
fmt.Println("test02中的arr:", arr)
}
test01中的arr: [88 22 33]
test02中的arr: &[88 22 33]
arr: [88 22 33]
長度問題
var age [...]{1,2,3} //長度3
var age [] //長度0 函式引數傳遞的時候不能把3傳0
var age [4]int //長度3不能傳4,要保持一致
var age [3]{3,4,5}
var chars [26]byte
for i := 0; i < 26; i++ {
chars[i] = 'A' + byte(i)
}
for i := 0; i < 26; i++ {
fmt.Printf("%c", chars[i])
}
//ABCDEFGHIJKLMNOPQRSTUVWXYZ
var intArr [6]int = [...]int{1, -1, 9, 99, 999, 9999} //宣告
maxVal := intArr[0]
maxIndex := 0
for i := 0; i < len(intArr); i++ {
for maxVal < intArr[i] {
maxVal = intArr[i]
maxIndex = i
}
}
fmt.Printf("maxVal=%v , maxIndex=%v", maxVal, maxIndex)
//maxVal=9999 , maxIndex=5
var intArr [5]int = [...]int{1, 9, 3, 4, 5}
sum := 0
for _, v := range intArr {
sum += v
}
fmt.Printf("sum=%v,avg=%v", sum, float64(sum)/float64(len(intArr)))
//都是int
var intArr3 [5]int
len := len(intArr3)
rand.Seed(time.Now().UnixNano())
for i := 0; i < len; i++ {
intArr3[i] = rand.Intn(100)
}
fmt.Println("交換前=", intArr3)
temp := 0
for i := 0; i < len/2; i++ {
temp = intArr3[len-1-i]
intArr3[len-1-i] = intArr3[i]
intArr3[i] = temp
}
fmt.Println("交換後=", intArr3)
交換前= [24 63 71 32 66]
交換後= [66 32 71 63 24]
切片
為什麼要切片?在元素個數不確定的情況下,使用陣列不知道開多大,大了浪費小了不夠用
切片英文slice
切片是陣列的一個引用,在進行傳遞時,遵守引用傳遞機制 【】
切片的使用和陣列基本相似(遍歷、訪問、求長度等)
切片的長度是可以變化的,動態變化
定義: var 切片名 []型別 比如: var age []int
切片的使用
var intArr [5]int = [...]int{1, 22, 33, 66, 99}
//slice := intArr[1:4] //表示slice 應用到intArr這個陣列
//intArr[1:3],起始下標包1不包3
slice := intArr[1:4]
fmt.Println("intArr=", intArr)
fmt.Println("slice元素是", slice)
fmt.Println("slice元素長度", len(slice))
fmt.Println("slice元素容量", cap(slice))
intArr= [1 22 33 66 99]
slice元素是 [22 33 66]
slice元素長度 3
slice元素容量 4
fmt.Printf("intArr[1]的地址=%p\n", &intArr[1])
fmt.Printf("intArr[0]的地址=%p slice[0]==%v\n", &slice[0], slice[0])
intArr[1]的地址=0xc0000ca038
intArr[0]的地址=0xc0000ca038 slice[0]==22
引用,包括地址、len長度、cap容量
//定義切片,引用陣列
var arr [5]int = [...]int{1, 2, 3, 4, 5}
var slice = arr[1:3]
fmt.Println("arr=", arr)
fmt.Println("slice=", slice)
fmt.Println("slice len=", len(slice))
fmt.Println("slice cap=", cap(slice))
arr= [1 2 3 4 5]
slice= [2 3]
slice len= 2
slice cap= 4
Var 切片名 []type = make([]type,len,[cap]) ;cap必須大於len
var slice []float64 = make([]float64, 5, 10)
slice[1] = 10
slice[3] = 20
fmt.Println("slice=", slice)
fmt.Println("slice len=", len(slice))
fmt.Println("slice cap=", cap(slice))
slice= [0 10 0 20 0]
slice len= 5
slice cap= 10
總結:
- make必須指定cap和len
- 沒有給切片元素複製,預設(int,float => 0 string=> “” bool=>false)
- make方式建立的切片對應的陣列由make底層維護不可見,只能通過slice去訪問各個元素
- 方式1和方式2的區別:1的陣列可見2的陣列不可見
var strSlice []string = []string{"tom", "jack", "rose"}
fmt.Println("strSlice=", strSlice)
fmt.Println("strSlice len=", len(strSlice))
fmt.Println("strSlice cap=", cap(strSlice))
strSlice= [tom jack rose]
strSlice len= 3
strSlice cap= 3
For 和for–range
var strSlice []string = []string{"tom", "jack", "rose", "who"}
aaSlice := strSlice[0:4]
for i := 0; i < len(aaSlice); i++ {
fmt.Printf("aaSlice[%v]=%v\n", i, aaSlice[i])
}
for i, v := range aaSlice {
fmt.Printf("aaSlice[%v]=%v\n", i, v)
}
aaSlice[0]=tom
aaSlice[1]=jack
aaSlice[2]=rose
aaSlice[3]=who
切片的使用注意
切片初始化 Var slice=[a:b]
cap是一個內建函式,用於統計切片的容量,即最大可以存放多少個元素
切片定義往後,還不能使用,因為切片本身是一個空的,需要讓其應用到一個陣列,或者make一個空間供切片來使用
切片可以繼續切片
appen動態追加,【slice3…是自己】
vare slice = arr[0:end] var slice=arr[:end]
vare slice = arr[start:len(arr)] var slice=arr[start:]
vare slice = arr[0:len(arr)] var slice=arr[:]
注意:
var strSlice []string = []string{"tom", "jack", "rose", "who"}
slice2 := strSlice[1:3]
slice3 := strSlice[1:2]
slice3[0] = "zhang"
fmt.Println("slice2=", slice2)
fmt.Println("slice3", slice3)
fmt.Println("strSlice=", strSlice)
---
slice2= [zhang rose]
slice3 [zhang]
strSlice= [tom zhang rose who]
//因為指向的是同一個空間,所以後面改這個值也會影響
var slice3 []int = []int{11, 22, 33}
slice3 = append(slice3, 400, 500, 600)
fmt.Println("slice3", slice3)
slice3 = append(slice3, slice3...)
fmt.Println("slice3", slice3)
---
slice3 [11 22 33 400 500 600]
slice3 [11 22 33 400 500 600 11 22 33 400 500 600]
append原理:
- append其實就是擴容
- go底層會建立一個新的陣列newArr(安裝擴容後大小)
- 將slice原來包含的元素拷貝到新的陣列newArr
- slice重新引用到newArr,底層不可見
再次強調切片是引用型別,傳遞時候遵守引用傳遞機制:【本質是操作一個空間】
var slice []int
var arr [5]int = [...]int{1, 2, 3, 4, 5}
slice = arr[:]
var slice2 = slice
slice2[0] = 10
fmt.Println("slice2", slice2)
fmt.Println("slice", slice)
fmt.Println("arr", arr)
---
slice2 [10 2 3 4 5]
slice [10 2 3 4 5]
arr [10 2 3 4 5]
切片的拷貝操作
切片使用copy內建函式完成拷貝
- copy(A,B),把B的值賦值給A,都是切片
- A,B空間獨立
- copy長度不夠就不管唄
var slice4 []int = []int{1, 2, 3, 4, 5}
var slice5 = make([]int, 10)
copy(slice5, slice4)
fmt.Println("slice4", slice4)
fmt.Println("slice5", slice5)
---
slice4 [1 2 3 4 5]
slice5 [1 2 3 4 5 0 0 0 0 0]
var a []int = []int{1, 2, 3, 4, 5}
var slice = make([]int, 1)
fmt.Println(slice)
copy(slice, a)
fmt.Println(slice)
---
[0]
[1]
函式中改變會影響到函式外部的改變:實參
var slice = []int{1, 2, 3, 4}
fmt.Println("slice", slice)
test(slice)
fmt.Println("test(slice)", slice)
}
func test(slice []int) {
slice[0] = 100
}
---
slice [1 2 3 4]
test(slice) [100 2 3 4]
string與slice
string底層是一個byte陣列,因此string也可以進行切片處理
String和切片在記憶體的形式,以 “abcd”畫記憶體示意圖
string是不可變的,不能通過Str[0]=”Z”方式來修改字串
如果要修改字串,可以先將string轉[]byte或者將 []rune-> 修改 ->重寫轉成string
str := "hello@atguige"
slice := str[6]
fmt.Println("slice", slice)
---
slice 97
---
str[0] = "z" //不可分配 string不可變
str := "hello@atguige" //atguige
slice := str[6:]
fmt.Println(slice) // atguige
str := "hello@atguige"
arr := []byte(str)
arr[0] = 'Z'
str = string(arr)
fmt.Println(str) //Zello@atguige
//英文和數字 []byte位元組來處理,漢字是3個位元組,因此會出現亂碼
string轉[]rune(切片,[]rune按字元處理)
str := "西京歡迎你"
arr := []rune(str)
arr[0] = '北'
str = string(arr)
fmt.Println(str) //北京歡迎你
說明:編寫一個函式 fbn(n int) ,要求完成
1) 可以接收一個 n int
2) 能夠將斐波那契的數列放到切片中
3) 提示, 斐波那契的數列形式:
arr[0] = 1; arr[1] = 1; arr[2]=2; arr[3] = 3; arr[4]=5; arr[5]=8
思路:
注意是1,1,2,3,5,8
func fbn(n int)([]uint64){
fbnSlice := make([]uint64,n)
fbnSlice[0] = 1
fbnSlice[1] = 1
for i := 2; i < n; i++ {
fbnSlice[i] = fbnSlice[i-1] + fbnSlice[i-2]
}
return fbnSlice
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結