See the micro-knowledge | Take you to see the similarities and differences between Slice and Array through memory

hi, everyone, my name is hhf.

There is such a Go interview question: Please tell the difference between slice and array?

This is simply a question of points. But how do you answer to satisfy the interviewer?

I will not post the answer to this question here. But I want to simply analyze the difference between slice and array in terms of memory.

Array

func main() {
  as := [4]int{10587}
  
  fmt.Println("as[0]:", as[0])
  fmt.Println("as[1]:", as[1])
  fmt.Println("as[2]:", as[2])
  fmt.Println("as[3]:", as[3])
}

This very simple code declares an array. Of course the output is simple enough.

Let's play a bit of fun now, how to access the elements in the array through abnormal means? Before doing this, you need to know the underlying structure of the array. In fact, it is very simple, a Go array is a continuous memory space. As shown below

Write a simple piece of code, we do not access elements through subscript access. Get the pointer of the corresponding position by moving the pointer.

func main() {
    as := [4]int{10587}

    p1 := *(*int)(unsafe.Pointer(&as))
    fmt.Println("as[0]:", p1)

    p2 := *(*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&as)) + unsafe.Sizeof(as[0])))
    fmt.Println("as[1]:", p2)

    p3 := *(*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&as)) + unsafe.Sizeof(as[0])*2))
    fmt.Println("as[2]:", p3)

    p4 := *(*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&as)) + unsafe.Sizeof(as[0])*3))
    fmt.Println("as[3]:", p4)
}

result:

as[0]: 10
as[1]: 5
as[2]: 8
as[3]: 7

The following figure demonstrates the process of obtaining the value of the corresponding position:

Slice

Also for this simple piece of code for slice:

func main() {
  as := []int{10587}
  
  fmt.Println("as[0]:", as[0])
  fmt.Println("as[1]:", as[1])
  fmt.Println("as[2]:", as[2])
  fmt.Println("as[3]:", as[3])
}

If you want to get the value of the corresponding position of the slice by moving the pointer, you still need to know the underlying structure of the slice. As shown in the figure:

func main() {
    as := []int{10587}

    p := *(*unsafe.Pointer)(unsafe.Pointer(&as))
    fmt.Println("as[0]:", *(*int)(unsafe.Pointer(uintptr(p))))
    fmt.Println("as[1]:", *(*int)(unsafe.Pointer(uintptr(p) + unsafe.Sizeof(&as[0]))))
    fmt.Println("as[2]:", *(*int)(unsafe.Pointer(uintptr(p) + unsafe.Sizeof(&as[0])*2)))
    fmt.Println("as[3]:", *(*int)(unsafe.Pointer(uintptr(p) + unsafe.Sizeof(&as[0])*3)))

    var Len = *(*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&as)) + uintptr(8)))
    fmt.Println("len", Len) 

    var Cap = *(*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&as)) + uintptr(16)))
    fmt.Println("cap", Cap) 
}

result:

as[0]: 10
as[1]: 5
as[2]: 8
as[3]: 7
len 4
cap 4

Using a pointer to take the elements in the underlying Data of a slice is slightly different from an array:

  • After taking the address of the slice variable as, the address of the SiceHeader is obtained, and the pointer is moved to obtain the Data, Len, and Cap of the slice.
  • So when we get the value of Data, what we get is the value of the first address of the array pointed to by Data.
  • Since this value is a pointer, it is necessary to obtain the pointer value of the real first address of the array for this value *Data
  • Then for this value &(*Data), get the real first address, and then move the pointer to this value to get the value in the slice array

Get slice cap and len:

Get the slice's Data:

Welcome to the public account. For more learning and learning materials to share, pay attention to the official account reply instructions:

  • Reply 0, get "Go Mianjing"
  • 回复 1,获取 《Go 源码流程图》


本文分享自微信公众号 - HHFCodeRv(hhfcodearts)。
如有侵权,请联系 [email protected] 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

{{o.name}}
{{m.name}}

Guess you like

Origin my.oschina.net/u/3162806/blog/5209586