以下は、Golang スライス (Slice) の基礎となるソース コードを皆さんに紹介する go 言語 チュートリアル コラムです。友人の参考になれば幸いです。必要!
スライスについて話す前に、配列について話しましょう。配列の 2 つの特徴
Go 配列は値型であり、代入および関数パラメーターの受け渡し操作により配列データ全体がコピーされます。
arr := [2]int{1,2}arr2 := arr fmt.Printf("%p %p",&arr ,&arr2)//切片slice1 := []int{1,2}slice2 := slice1 fmt.Printf("%p %p",slice1 ,slice2)
スライスは配列の連続セグメントへの参照であるため、スライスは参照型であり、スライスは可変長の配列です。
スライスのデータ構造は次のように定義されます:
runtime/slice.go#L13
type slice struct { array unsafe.Pointer len int cap int}
src/runtime/slice.go #L83
func makeslice(et *_type, len, cap int) unsafe.Pointer { mem, overflow := math.MulUintptr(et.size, uintptr(cap)) .... return mallocgc(mem, et, true)}
基本的なロジックは、容量に基づいてメモリを適用することです。
func growslice(et *_type, old slice, cap int) slice { ... // 如果新要扩容的容量比原来的容量还要小,直接报panic if cap 6fcbe6a181235a2d91480a84b8bdbb32 doublecap { newcap = cap } else { // 旧容量 小于1024,新容量= 旧容量 * 2 也就是扩容1倍 if old.cap c9221202ba118f4c45c4e2fcde42ff0d 0 && writeBarrier.enabled { bulkBarrierPreWriteSrcOnly(uintptr(p), uintptr(old.array), lenmem-et.size+et.ptrdata) } } //移动到p memmove(p, old.array, lenmem) //返回slice结构,让slice.array指向p return slice{p, old.len, newcap}}
arr := make([]int,1024) arr = append(arr,1) fmt.Println(len(arr),cap(arr))// 1025,1280 arr1 := make([]int,10) arr1 = append(arr1,1) fmt.Println(len(arr1),cap(arr1))//11 20
arr := []int{1,2,3,4} arr1 := arr[:2] //[1,2] arr1 = append(arr1,5) fmt.Println(arr[3]) //5 修改了底层数组 //例子2 arr3 := []int{1,2,3,4} arr4 := arr3[2:] arr4 = append(arr4,10)//扩容 不会影响arr3 fmt.Println(arr3)
//toPtr 目标地址 toLen目标长度 // width 元素大小 func slicecopy(toPtr unsafe.Pointer, toLen int, fromPtr unsafe.Pointer, fromLen int, width uintptr) int { //判断长度 if fromLen == 0 || toLen == 0 { return 0 } n := fromLen if toLen < n { n = toLen } //切片大小等于0 if width == 0 { return n } size := uintptr(n) * width //特殊处理 如果只有一个元素并且大小是1byte,那么指针直接转换即可 if size == 1 { *(*byte)(toPtr) = *(*byte)(fromPtr) } else { //从 fm.array 地址开始,拷贝到 to.array 地址之后 memmove(toPtr, fromPtr, size) } return n }
以上がGolang Slice の基礎となるソースコードを読むの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。