1.切片 VS 數(shù)組
| 列表 | 數(shù)組 | 切片 |
|---|---|---|
| 類型 | 值類型 | 引用類型 |
| 長度 | 初始化后長度是固定的 | 長度可以變化 |
| 初始化方法① | [5] int {1,2} | s :=make([]int,len,cap) //內(nèi)置函數(shù)make()初始化 .初始化時len=cap,在追加元素時如果容量cap不足時將按len的2倍擴(kuò)容 |
| 初始化方法② | [...] int {1,2,3,4,5};//有....自動計算 | s :=[] int {1,2,3 } //直接初始化切片,[]表示是切片類型,{1,2,3}初始化值依次是1,2,3.其cap=len=3 |
| 初始化方法③ | [5] int { 2:1,3:2,4:3}; | s := arr[startIndex:endIndex] //將arr中從下標(biāo)startIndex到endIndex-1 下的元素創(chuàng)建為一個新的切片 |
| 初始化方法④ | [...] int {2:1,4:3}//長度為5的數(shù)組,起元素值依次為:0,0,1,0,3。由于指定了最大索引4對應(yīng)的值3,根據(jù)初始化的元素個數(shù)確定其長度為5賦值與使用 | xx |
| 訪問方法① | 通過下標(biāo)訪問元素,可修改其元素值:arr[1] | 同左 |
| 訪問方法② | 通過for遍歷數(shù)組元素:for index, value := range arr | 同左 |
| 其他 | 你將一個數(shù)組賦值給另外一個數(shù)組,那么,實際上就是將整個數(shù)組拷貝一份(匿名拷貝)改變原值,則新值不會變 | 添加:①s :=append(s,1,2,3,4);②s :=append(s,s1...) |
切片本身并不是動態(tài)數(shù)組或者數(shù)組指針。它內(nèi)部實現(xiàn)的數(shù)據(jù)結(jié)構(gòu)通過指針引用底層數(shù)組,設(shè)定相關(guān)屬性將數(shù)據(jù)讀寫操作限定在指定的區(qū)域內(nèi)。切片本身是一個只讀對象,其工作機(jī)制類似數(shù)組指針的一種封裝。
切片三要素:
指針:指向地址
長度:len
容量:cap
切片初始化,len=cap
切片是引用類型(新地址,指向原地址上的值),最大的特點是,引用的地址上值改變,切片也會改變
slice := []int{1, 2, 3} //剛開始len=cap
newSlice := append(slice, 4, 5) //擴(kuò)容,觸發(fā)了拷貝(新建地址)
newnewSlice := slice[:] //切片的引用
slice[0] = 88
fmt.Printf("slice:%+v, newSlice:%+v, newnewSlice:%+v\n", slice, newSlice, newnewSlice)
//slice:[88 2 3], newSlice:[1 2 3 4 5], newnewSlice:[88 2 3]
另外,數(shù)組作為函數(shù)的參數(shù),那么實際傳遞的參數(shù)是一份數(shù)組的拷貝,而不是數(shù)組的指針。
所以函數(shù)中對數(shù)組改變,返回后數(shù)組不會改變
A(arr)
func A(arr []int){
arr[0]=9
}
1.切片vs數(shù)組
2.切片是引用傳遞,所以它們不需要使用額外的內(nèi)存并且比使用數(shù)組更有效率。
3.空切片 vs nil切片
4.切片擴(kuò)容:
4.1 擴(kuò)容策略
如果切片的容量小于 1024 個元素,于是擴(kuò)容的時候就翻倍增加容量。上面那個例子也驗證了這一情況,總?cè)萘繌脑瓉淼?個翻倍到現(xiàn)在的8個。
一旦元素個數(shù)超過 1024 個元素,那么增長因子就變成 1.25 ,即每次增加原來容量的四分之一。(××××××××××錯,發(fā)現(xiàn)了1,2,4,6,8規(guī)律)
注意:擴(kuò)容擴(kuò)大的容量都是針對原來的容量而言的,而不是針對原來數(shù)組的長度而言的。
4.2擴(kuò)容是生成全新的內(nèi)存地址還是在原來的地址后追加?
4.2.1 slice創(chuàng)建方法一:【分?jǐn)U容情況,是否擴(kuò)容】
slice := []int{10, 20, 30, 40}
newSlice := append(slice, 50)
Go 默認(rèn)會先開一片內(nèi)存區(qū)域,把原來的值拷貝過來,然后再執(zhí)行 append() 操作。這種情況絲毫不影響原數(shù)組。
4.2.2 切片字面量創(chuàng)建【新地址】
由于原數(shù)組還有容量可以擴(kuò)容,所以執(zhí)行 append() 操作以后,會在原數(shù)組上直接操作,所以這種情況下,擴(kuò)容以后的數(shù)組還是指向原來的數(shù)組。
array := [4]int{10, 20, 30, 40}
slice := array[0:2]
newSlice := append(slice, 50)
func main() {
arrayA := [2]int{100, 200}
testArrayPoint(&arrayA) // 1.傳數(shù)組指針
arrayB := arrayA[:]
testArrayPoint(&arrayB) // 2.傳切片 ****
fmt.Printf("arrayA : %p , %v\n", &arrayA, arrayA)
}
func testArrayPoint(x *[]int) {
fmt.Printf("func Array : %p , %v\n", x, *x)
(*x)[1] += 100
}
打印結(jié)果:
func Array : 0xc4200b0140 , [100 200]
func Array : 0xc4200b0180 , [100 300]
arrayA : 0xc4200b0140 , [100 400]
并非所有時候都適合用切片代替數(shù)組,因為切片底層數(shù)組可能會在堆上分配內(nèi)存,而且小數(shù)組在棧上拷貝的消耗也比make 消耗小
2. map
sync/atomic的使用
Go之 unsafe.Pointer
- context
學(xué)習(xí)鏈接
總結(jié):
- 關(guān)于cancel
withCance 會傳遞 cancel信號到子context中。
如果某層context cancel了,則會向它的所有子值(或者說子節(jié)點)傳達(dá)撤銷信號。這些子值會如法炮制,把撤銷信號繼續(xù)傳播下去。最后,這個Context值會斷開它與其父值之間的關(guān)聯(lián)。
- 關(guān)于cancel
2.關(guān)于context 中的value
設(shè)置傳遞時,會傳遞到所有子context中。
取值key時,回去查找本context,如果沒找到key,會向上去查找所有父的context查找- 關(guān)于grpc的timeout
客戶端調(diào)用時,加了timeout參數(shù),會在http2的header中添加grpc-timeout參數(shù)
服務(wù)端獲取參數(shù),判斷相關(guān)邏輯。
- 關(guān)于grpc的timeout