package main
func a(a) []int {
a1 := []int{3}
a2 := a1[1:]
return a2
}
func main(a) {
a()
}
Copy the code
What’s your first reaction to this question?
(A) Error: panic: Runtime error: index out of range [1] with length 1 (C) [] (DCopy the code
First impression: it will compile, but it will panic at runtime. But contrary to our expectations, it actually works, and the result is :[]
doubt
a1 := []int{3}
a2 := a1[1:]
fmt.Println("a[1:]", a2)
Copy the code
If len(a1) = 1 and len(a1) = 1, a1[1] will panic, but a[1:] will output normally.
Look at the surface
Look at the big picture
a1 := []int{3}
fmt.Printf("len:%d, cap:%d".len(a1), cap(a1))
fmt.Println("a[0:]", a1[0:])
fmt.Println("a[1:]", a1[1:])
fmt.Println("a[2:]", a1[2:)Copy the code
Results:
len:1, cap:1
a[0:]: [1]
a[1:] []
panic: runtime error: slice bounds out of range [2:1]
Copy the code
From the surface, panic started from a[2:], who on earth caused such a result?
Compilation to see at a glance
"". A STEXT size=87 args=0x18 locals=0x18 0x0028 00040 (main.go:6) CALL runtime.newobject(SB) 0x002d 00045 (main.go:6) MOVQ 8(SP), 0x003200050 (main.go:6) MOVQ $3, (AX) ~r0+32(SP) 0x003e 00062 (main.go:8) XORPS X0, ~r0+40(SP) // Put X0 into the return value 0x0046 00070 (main.go:8) MOVQ 16(SP), BP 0x004B 00075 (main.go:8) ADDQ $24, SP 0x004F 00079 (main.go:8) RET // Omitted....Copy the code
These are the two lines that I really care about.
0x0041 00065 (main.go:8) MOVUPS X0, "".~r0+40(SP) // Put X0 into the return valueCopy the code
A [1:] does not call Runtime.panicsliceb (SB), but returns an empty slice. Why is that?
If you’re skeptical, go to Github and pick up an issue. github.com/golang/go/i…
Conclusion: This is intentional, simply to maintain reslice symmetry. This explains why an empty slice is returned.
Reslice principle
With that explained, let’s go back to the normal reslice example
func a(a) []int {
a1 := []int{3.4.5.6.7.8}
a2 := a1[2:]
return a2
}
Copy the code
Let’s use a simple diagram to describe the reslice relationship between A1 and A2 in this code. You can see that A1 and A2 share the underlying array.
If you know these things, then slice should be used with little problem.
Have you considered the following questions?
- How do A1 and A2 share the underlying array?
- A1 [Low :high] How is it implemented?
Continue to look at the assembly of this code:
"". A STEXT size=117 args=0x18 locals=0x18 0x0028 00040 (main.go:4) CALL runtime.newobject(SB) 0x002d 00045 (main.go:4) MOVQ 8(SP), AX 0x0032 00050 (main.go:4) MOVQ $3, (AX) 0x0039 00057 (main.go:4) MOVQ $4, 8(AX) 0x0041 00065 (main.go:4) MOVQ $5, 16(AX) 0x0049 00073 (main.go:4) MOVQ $6, 24(AX) 0x0051 00081 (main.go:4) MOVQ $7, 32(AX) 0x0059 00089 (main.go:4) MOVQ $8, 40(AX) 0x0061 00097 (main.go:5) ADDQ $16, AX 0x0065 00101 (main.go:6) MOVQ AX, "".~r0+32(SP) 0x006a 00106 (main.go:6) MOVQ $4, "".~r0+40(SP) 0x0073 00115 (main.go:6) MOVQ $4, "".~r0+48(SP) 0x007c 00124 (main.go:6) MOVQ 16(SP), BP 0x0081 00129 (main.go:6) ADDQ $24, SP 0x0085 00133 (main.go:6) RET // Omit....Copy the code
- Line 4: move the top AX stack pointer down 8 bytes to point to the address space that a1’s data points to
- Line 5-10: put [3,4,5,6,7,8] into the address space pointed to by data in a1
- Line 11: AX pointer is moved back 16 bytes. It’s going to point to element 5
- Line 12: Move the SP pointer down 32 bytes to the slice to be returned (which is actually a2) and place AX into the SP. Note that AX is a pointer to SP, which causes a1 and A2 to share the same memory space
- Line 13: Move the SP pointer 40 bytes down to the len of a2 and put 4 into SP, where len(a2) = 4
- Line 14: Move the SP pointer down 48 bytes to point to cap of a2 and put 4 into SP, where cap(a2) = 4
The following is a stack diagram of slice, which can be viewed in conjunction with the above assembly.
If you see it here, it’s pretty clear. This leads to the following conclusions:
- Reslice is implemented entirely in assembly
- When reslice, slice data is completed through pointer movement, resulting in the sharing of the same underlying data, and new Len and cap are placed in the corresponding position at the same time
At this point, golang Reslice’s basic principle is clear.
The resources
- Get down to the bottom of Go and get you close to a group of people with aspirations
- Assembler view of Slice, a new world
- Why slice not painc
- Slice expressions
- A Quick Guide to Go’s Assembler
- Plan9 Assembly is fully parsed