首先我們來看段**的輸出
s := make(int, 4)
for i := 0; i < 4; i++
s0 := s[0]
fmt.println(s)
輸出的結果是
[[1 0 0 0] [1 0 0 0] [1 0 0 0] [1 0 0 0]]
帶著這些疑問,我們來看看slice的底層實現。
slice的結構
type slice struct
array指向乙個陣列元素的位址,這個陣列可能在makeslice時建立,也可能之前就存在,而slice被"attach"上去,例如 s := a[0:5];
//**比較簡單
func makeslice(et *_type, len, cap int) slice
if cap < len || uintptr(cap) > maxelements
//分配陣列空間
p := mallocgc(et.size*uintptr(cap), et, true)
return slice
}
e.g.
s := make(int, 1, 3)
fmt.printf("%p, %v, len:%d, cap:%d", unsafe.pointer(&s[0]), s, len(s), cap(s))
輸出:
0xc42007c0a0, [0], len:1, cap:3
對於直接"attach"到陣列的情形,類似下面這樣
a := [10]int
fmt.printf("%p, %v \n", &a, a)
s1 := a[1:5:7]
fmt.printf("%p, %v, len:%d, cap:%d, self:%p \n", unsafe.pointer(&s1[0]), s1, len(s1), cap(s1), unsafe.pointer(&s1) )
輸出:
0xc42006e050, [0 1 2 3 4 5 6 7 8 9]
0xc42006e058, [1 2 3 4], len:4, cap:6, self:0xc42006c140
根據兩個指標的關係,可以看出,slice直接指向了陣列中的元素
同理,slice2還可以通過另乙個slice1構造,但其屬性依賴slice1,並不是slice1底層的陣列
s2 := s1[2:]
fmt.printf("%p, %v, len:%d, cap:%d, self:%p \n", unsafe.pointer(&s2[0]), s2, len(s2), cap(s2), unsafe.pointer(&s2) )
輸出
修改slice中元素的值,實際上修改的是底層陣列元素的值
s2[0] = 100
fmt.println(a, s1, s2)
輸出
[0 1 2 100 4 5 6 7 8 9] [1 2 100 4] [100 4]
擴張
先上**
func growslice(et *_type, old slice, cap int) slice
return slice
}// 計算新的cap,針對不同情況分別處理
newcap := old.cap
doublecap := newcap + newcap
if cap > doublecap else else }}
var lenmem, newlenmem, capmem uintptr
const ptrsize = unsafe.sizeof((*byte)(nil))
switch et.size
......
var p unsafe.pointer
if et.kind&kindnopointers != 0 else else }}
return slice
}
fmt.printf("%p, %v \n", unsafe.pointer(&s2[0]), s2)
fmt.println(a, s1, s2)
fmt.printf("len(s1)=%d, cap(s1)=%d, len(s2)=%d, cap(s2)=%d", len(s1), cap(s1), len(s2), cap(s2)) 輸出
[0 1 2 100 4 1000 6 7 8 9] [1 2 100 4] [100 4 1000]
len(s1)=4, cap(s1)=6, len(s2)=3, cap(s2)=4
fmt.printf("%p, %v \n", unsafe.pointer(&s2[0]), s2)
fmt.println(a, s1, s2)
fmt.printf("len(s1)=%d, cap(s1)=%d, len(s2)=%d, cap(s2)=%d", len(s1), cap(s1), len(s2), cap(s2)) 輸出
0xc420014280, [100 4 1000 1001 1002]
[0 1 2 100 4 5 6 7 8 9] [1 2 100 4] [100 4 1000 1001 1002]
len(s1)=4, cap(s1)=6, len(s2)=5, cap(s2)=8
原陣列a,切片s1的屬性未受影響;但s2底層的陣列已發生變化,cap也是之前的2倍。
1、多個slice指向相同的底層陣列時,修改其中乙個slice,可能會影響其他slice的值;
2、slice作為引數傳遞時,比陣列更為高效,因為slice的結構比較小;
3、slice在擴張時,可能會發生底層陣列的變更及記憶體拷貝;
4、因為slice引用了陣列,這可能導致陣列空間不會被gc,當陣列空間很大,而slice引用內容很少時尤為嚴重;
ConcurrentHashMap底層實現
concurrenthashmap融合了hashtable和hashmap二者的優勢 hashtable是做了同步的,hashmap沒有同步,所以hashmap在單執行緒情況下效率高,hashtable在多執行緒情況下,同步操作能保證程式執行的正確性 但是hashtable每次同步執行都要鎖住整個結...
golang slice 與list 的效能分析。
一 比較slice 與 list 遍歷建立和新增元素速度。package main import time fmt container list func main fmt.println slice 建立速度 time.now sub t string t time.now l list.new ...
Golang slice的用法以及和陣列的區別
說明 slice是go的乙個語言特性,其實有點類似於cpp的vector,可變長度,可以擴充套件空間。今天詳細看了下,做下總結。slice本質上是乙個區間,原型是t,大致的實現是這樣的 type slice struct可以看到的是是乙個指向陣列的指標,那麼在修改slice的時候會改變陣列的值。用法...