Two-dimensional slice


Go supports multiple-dimensional slice, but I only want to introduce two-dimensional slice here. One reason is the two-dimensional slice is usually used in daily life, while multiple-dimensional seems not common. If you often use multiple-dimensional slice, personally I think the code is a little clumsy and not easy to maintain, so maybe you can try to check whether there is a better method; the other reason is the principle behind multiple-dimensional slice is the same with two-dimensional slice, you can also understand it if you know two-dimensional slice well.

Let’s the following example:

  1. package main
  2. import "fmt"
  3. func main() {
  4. s := make([][]int, 2)
  5. fmt.Println(len(s), cap(s), &s[0])
  6. s[0] = []int{1, 2, 3}
  7. fmt.Println(len(s[0]), cap(s[0]), &s[0][0])
  8. s[1] = make([]int, 3, 5)
  9. fmt.Println(len(s[1]), cap(s[1]), &s[1][0])
  10. }

I still use gdb to inspect the execution flow:

  1. 5 func main() {
  2. (gdb) n
  3. 6 s := make([][]int, 2)
  4. (gdb)
  5. 7 fmt.Println(len(s), cap(s), &s[0])
  6. (gdb)
  7. 2 2 &[]
  8. 9 s[0] = []int{1, 2, 3}
  9. (gdb) p &s
  10. $1 = (struct [][]int *) 0xc82003fe70
  11. (gdb) x/24xb 0xc82003fe70
  12. 0xc82003fe70: 0x40 0x02 0x01 0x20 0xc8 0x00 0x00 0x00
  13. 0xc82003fe78: 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00
  14. 0xc82003fe80: 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00

s is a slice (the start memory address is 0xc82003fe70), but its elements are also slices. Let’s check the elements:

  1. (gdb) x/48xb 0xc820010240
  2. 0xc820010240: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
  3. 0xc820010248: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
  4. 0xc820010250: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
  5. 0xc820010258: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
  6. 0xc820010260: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
  7. 0xc820010268: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

All the memory content are 0, nothing exciting! Continue to step by step:

  1. (gdb) n
  2. 10 fmt.Println(len(s[0]), cap(s[0]), &s[0][0])
  3. (gdb)
  4. 3 3 0xc82000e220
  5. 12 s[1] = make([]int, 3, 5)

Now since s contains a valid slice element, check its underlying array:

  1. (gdb) x/48xb 0xc820010240
  2. 0xc820010240: 0x20 0xe2 0x00 0x20 0xc8 0x00 0x00 0x00
  3. 0xc820010248: 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00
  4. 0xc820010250: 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00
  5. 0xc820010258: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
  6. 0xc820010260: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
  7. 0xc820010268: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

Yeah, the memory has been updated by the pointer, length and capacity of s[0], the same with previous output from fmt.Println. Check the underlying array of s[0]:

  1. (gdb) x/24xb 0xc82000e220
  2. 0xc82000e220: 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00
  3. 0xc82000e228: 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00
  4. 0xc82000e230: 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00

We can see 3 elements: 1, 2, 3.

Following the same method to check the s[1]:

  1. (gdb) n
  2. 13 fmt.Println(len(s[1]), cap(s[1]), &s[1][0])
  3. (gdb)
  4. 3 5 0xc820010270
  5. 14 }
  6. (gdb) x/48xb 0xc820010240
  7. 0xc820010240: 0x20 0xe2 0x00 0x20 0xc8 0x00 0x00 0x00
  8. 0xc820010248: 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00
  9. 0xc820010250: 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00
  10. 0xc820010258: 0x70 0x02 0x01 0x20 0xc8 0x00 0x00 0x00
  11. 0xc820010260: 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00
  12. 0xc820010268: 0x05 0x00 0x00 0x00 0x00 0x00 0x00 0x00
  13. (gdb) x/40xb 0xc820010270
  14. 0xc820010270: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
  15. 0xc820010278: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
  16. 0xc820010280: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
  17. 0xc820010288: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
  18. 0xc820010290: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

Now, we can see s contains all the info of its slice elements, and the elements of s[1] are initialized to 0.