Technical Article => Programming => Go

There are 3 components of slice:

a) Pointer: Points to the start position of slice in the underlying array;

b) length (type is int): the number of the valid elements of the slice;

b) capacity (type is int): the total number of slots of the slice.

Check the following code:

package main import ( "fmt" "unsafe" ) func main() { var s1 []int fmt.Println(unsafe.Sizeof(s1)) }

The result is 24 on my 64-bit system (The pointer and int both occupy 8 bytes).

In the next example, I will use gdb to poke the internals of slice. The code is like this:

package main import "fmt" func main() { s1 := make([]int, 3, 5) copy(s1, []int{1, 2, 3}) fmt.Println(len(s1), cap(s1), &s1[0]) s1 = append(s1, 4) fmt.Println(len(s1), cap(s1), &s1[0]) s2 := s1[1:] fmt.Println(len(s2), cap(s2), &s2[0]) }

Use gdb to step into the code:

5 func main() { (gdb) n 6 s1 := make([]int, 3, 5) (gdb) 7 copy(s1, []int{1, 2, 3}) (gdb) 8 fmt.Println(len(s1), cap(s1), &s1[0]) (gdb) 3 5 0xc820010240

Before executing " s1 = append(s1, 4) ", fmt.Println outputs the length(3), capacity(5) and the starting element address(0xc820010240) of the slice, let's check the memory layout of s1:

10 s1 = append(s1, 4) (gdb) p &s1 $1 = (struct []int *) 0xc82003fe40 (gdb) x/24xb 0xc82003fe40 0xc82003fe40: 0x40 0x02 0x01 0x20 0xc8 0x00 0x00 0x00 0xc82003fe48: 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xc82003fe50: 0x05 0x00 0x00 0x00 0x00 0x00 0x00 0x00 (gdb)

Through examining the memory content of s1(the start memory address is 0xc82003fe40 ), we can see its content matches the output of fmt.Println .

Continue executing, and check the result before "s2 := s1[1:]":

(gdb) n 11 fmt.Println(len(s1), cap(s1), &s1[0]) (gdb) 4 5 0xc820010240 13 s2 := s1[1:] (gdb) x/24xb 0xc82003fe40 0xc82003fe40: 0x40 0x02 0x01 0x20 0xc8 0x00 0x00 0x00 0xc82003fe48: 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xc82003fe50: 0x05 0x00 0x00 0x00 0x00 0x00 0x00 0x00

We can see after appending a new element( s1 = append(s1, 4) ), the length of s1 is changed to 4 , but the capacity remains the original value.

Let's check the internals of s2:

(gdb) n 14 fmt.Println(len(s2), cap(s2), &s2[0]) (gdb) 3 4 0xc820010248 15 } (gdb) p &s2 $3 = (struct []int *) 0xc82003fe28 (gdb) x/24hb 0xc82003fe28 0xc82003fe28: 0x48 0x02 0x01 0x20 0xc8 0x00 0x00 0x00 0xc82003fe30: 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xc82003fe38: 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00

The element start address of s2 is 0xc820010248 , actually the second element of s1( 0xc82003fe40 ), and the length(3) and capacity(4) are both one less than the counterparts of s1(4 and 5 respectively).

Note: the post is authorized to republish here by the author Nan Xiao, a system software engineer living in China, the original post can be found here.