Home > Article > Backend Development > Read the underlying source code of Golang Slice
The following is the go languagetutorial column to introduce the underlying source code of Golang slice (Slice) to everyone, I hope it will be helpful to friends in need!
Before talking about slicing, let’s talk about the array. Two characteristics of the array
Go arrays are value types, and assignment and function parameter passing operations will copy the entire array data.
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)
A slice is a reference to a continuous segment of an array, so a slice is a reference type. A slice is an array of variable length.
The data structure of Slice is defined as follows:
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)}
The basic logic is to apply for a piece of memory based on capacity.
Expansion is when the length of the slice is greater than the capacity and the underlying array cannot fit in it
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)
src/runtime/slice.go#L247
//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 }
The above is the detailed content of Read the underlying source code of Golang Slice. For more information, please follow other related articles on the PHP Chinese website!