panic
A: = make (int [], 3, 4) a [0] = 1 a [1] = 2 a [2] [3] = 4 = 3 aCopy the code
Although the capacity of A is 4, since the length of slice specified at the initial initialization is 3, a[3] will go out of bounds and panic will occur
panic: runtime error: index out of range [4] with length 3
Copy the code
So what does this 4 do?
structure
type slice struct {
array unsafe.Pointer
len int
cap int
}
Copy the code
- The bottom layer of slice is an array, so there is a pointer to the bottom array
- Slice has its own length, len
- Slice has its own capacity cap
Slice capacity
Cap is used for capacity expansion. If you expect your slice to cram a lot of data into it as the application runs, you can make the cap larger to avoid frequent memory requests during capacity expansion.
Nonsense not to say, directly on the source code
newcap := old.cap
doublecap := newcap + newcap
if cap > doublecap {
newcap = cap
} else {
if old.len < 1024 {
newcap = doublecap
} else {
// Check 0 < newcap to detect overflow
// and prevent an infinite loop.
for 0 < newcap && newcap < cap {
newcap += newcap / 4
}
// Set newcap to the requested cap when
// the newcap calculation overflowed.
if newcap <= 0 {
newcap = cap
}
}
}
Copy the code
This is the core code for Slice expansion, and a good command of it will blow the interviewer away. This is the code for go1.15, there may be differences in older versions. By reading the source code, you can summarize:
- If the new capacity is twice as large as the old capacity, the new capacity is used
S: = make s = (int [], 3, 3) append (s, 4, 7) FMT. Println (cap (s)) / / 8Copy the code
Initialize cap=3, append 4 elements in a row, need new capacity =7, but cap*2=6, so according to the code should be 7, but the test found 8. And that’s because go has subsequent logic that says if it’s odd, then it’s going to add 1.
2. If 1 is not sufficient, if the number of old elements is less than 1024, then the new capacity is twice the original capacity
S: = make s = (int [], 3, 3) append (s, 4) FMT. Println (cap (s)) / / 6Copy the code
At this time, only one capacity is expanded. Theoretically, the new capacity needs to be at least 4, less than 2* CAP =6, so the result is 6.
- If 1 is not satisfied and the number of old elements is greater than or equal to 1024, the old cap keeps multiplying by 1.25 until it is larger than the new capacity
s:=make([]int,1024)
add:=make([]int,570)
s = append(s,add...)
fmt.Println(cap(s))//1696
Copy the code
1280*1.25=1600>1594, cap=1600? However, the fact is 1696. Through the background debug, it is found that 1600 is indeed calculated from the above nuclear code, but it is not finished yet.
case et.size == sys.PtrSize:
lenmem = uintptr(old.len) * sys.PtrSize
newlenmem = uintptr(cap) * sys.PtrSize
capmem = roundupsize(uintptr(newcap) * sys.PtrSize)
overflow = uintptr(newcap) > maxAlloc/sys.PtrSize
newcap = int(capmem / sys.PtrSize)
Copy the code
This code is going to be 1696.
Make with the new
- Make can only be used with slice, map, and chan to return the object itself
- The definition of a new parameter is a data type, which can be an int, string, struct, map, or slice. Instead of returning the object itself, it returns a pointer to the object
func new(Type) *Type
Copy the code
SAO operation:
aa:=new([]int)
*aa = append(*aa,1)
fmt.Println((*aa)[0]) // 1
Copy the code
Let’s just say it’s either a genius or an idiot
Empty slice versus nil slice
I have to say that Go is really magical, but let me give you an idea
- Nil slice: Len =0 cap=0; pointer=0
- Len =0 cap=0 pointer! = 0
When will nil and empty slice be created
nil | empty |
---|---|
var a []int | a:=make([]int,0) |
a:=*new([]int) | a:=[]int{} |
Official advice: Use nil slice
var a1 []int a2:=*new([]int) a3:=make([]int,0) a4:=[]int{} fmt.Println(*(*[3]int)(unsafe.Pointer(&a1))) //[0 0 0] fmt.Println(*(*[3]int)(unsafe.Pointer(&a2))) //[0 0 0] fmt.Println(*(*[3]int)(unsafe.Pointer(&a3))) //[824634109648 0 0] fmt.Println(*(*[3]int)(unsafe.Pointer(&a4))) //[824634109648 0 0]Copy the code
The address of the empty slice is the same, pointing to an address that has no space
var zerobase uintptr
if size == 0 {
return unsafe.Pointer(&zerobase)
}
Copy the code