切片與陣列
go的陣列是這樣的
array := [3]int{1,2,3}
array := [...]int{1,2,3}
go的切片
array := []int{1,2,3} //1
array := make([]int,2) //2
arr := [5]int{1,2,3,4,5}
array :=arr[1:3] //底層陣列可見 會修改原陣列
len和cap的區別
make切片有兩個引數len和cap
len:代表底層陣列可訪問的范圍 用索引訪問不可越過這個界限
cap:代表底層陣列的長度,如果append元素時沒有超過這個cap,則不再創建底層陣列,否則開辟新的空間,同時增大cap(這里有一個增大規則),所以如果適當設定大一些的cap還是能減少開銷的
array := make([]int,2,5) //len=2 cap=5
array := make([]int,2) //make([]int,2,2)
arr = [9]int{1,2,3,4,5,6,7,8,9}
arr2 :=arr[2:5:6] //長度為 5-2 容量為6-2
切片傳參
func Args(arr ...int){
}
Args(1,2,3,4,5)
這里arr的型別就是切片型別
切片的底層結構
runtime/slice.go
type slice struct {
array unsafe.Pointer
len int
cap int
}
unsafe.Pointer其實就是*int型別 指向記憶體地址
切片為什么是參考型別?
切片傳入函式,同樣也是值傳遞,會copy一份切片的值傳入函式內,哪為什么又說是參考型別呢?為什么函式內部改變會影響原切片呢?
根據上面的切片底層結構我們知道,切片有一個指向底層陣列的指標,雖然切片是傳值復制了一份,同時指向底層陣列的指標也復制了一份,但指標始終是指向同一個地址的,那么我們改變切片的值其實就是改變底層陣列的值,因為他們還是共享底層地址的,
遍歷切片的優化
我們知道,切片可以用range遍歷
//耗時 因為要建立新的變數
for _,v:=range arrStr{
log.Println("執行操作:",v)
}
下面做一些優化,忽略值,而是用索引來,這樣就不用再開辟空間創建一個變數并且賦值給變數了
//優化
arrStr:=[]string{"a","b","c","d"}
for key:=range arrStr{
log.Println("[優化]執行操作:",arrStr[key])
}
空切片的判斷
空切片可以判斷它的長度是否為0,但是判斷為nil來判斷這個切片是否為空是不準確的,
比如下面兩種情況就要用len是否為0來判斷:
empty1:=make([]int,0)
log.Println(empty1==nil) //false
empty1=[]int{}
log.Println(empty1==nil)
下面的就是為nil 因為這只是宣告,而沒有開辟地址
var empty2 []int
log.Println(empty2==nil) //true
切片的克隆
剛學習go切片的新手可能會進行最簡單的操作
a := []int{1, 2, 3}
b := make([]int, len(a)) //使用copy函式必須復制切片的結構必須和源資料結構一致
copy(b, a)
上面的操作進行了很多不必要的作業,開辟空間等等...讓代碼看起來不是很簡潔,記憶體也有一定開銷,當然這里影響很小,再看如下的clone
arrStr:=[]string{"a","b","c","d"}
arrStrClone:=append(arrStr[:0:0],arrStr...)
這個操作筆者以前也沒見過,但是看了大佬的書籍才學會的這種騷操作,代碼很簡潔
洗掉切片的元素
洗掉一段切片,如下,洗掉了 [1-3) 的元素,洗掉后為[a,d,e,f] 注意是前閉后開的
arrStrClone=[]string{"a","b","c","d","e","f"}
arrStrClone = append(arrStrClone[:1], arrStrClone[3:]...)
洗掉一個元素
其實是洗掉一段元素的特例,這里就不舉例了
切片的插入
如何在切片中插入切片呢?或者在切片中插入元素呢?
其實和洗掉的思想是一樣的
// Push(插入到結尾)
s = append(s, elements...)
// Unshift(插入到開頭)
s = append(elements, s...)
//將切片elements的元素插入到s切片的i位置之后
s = append(s[:i], append(elements, s[i:]...)...)
切片實作堆疊佇列
出
s, e = s[1:], s[0] //shift操作 將開頭元素彈出
s, e = s[:len(s)-1], s[len(s)-1] //pop 將尾元素彈出
入
// Push(插入到結尾)
s = append(s, elements...)
// Unshift(插入到開頭)
s = append(elements, s...)
關于并發
注意,go里面的特殊容器都是現成不安全的,多個并發讀取可以,但是并發修改是不允許的
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/36309.html
標籤:Go
下一篇:Go module學習筆記
