网站首页 返回列表 像“草根”一样,紧贴着地面,低调的存在,冬去春来,枯荣无恙。

go语言slice数据类型的定义和使用

2020-06-10 02:57:46 admin 776

这篇文章介绍go语言slice数据类型的定义,内部格式,以及如何声明和定义slice类型变量。

slice数据类型大小

__

  1. package main
  2. import (
  3. "fmt"
  4. "unsafe"
  5. )
  6. func main() {
  7. var s1 []int64
  8. var s2 []int64 = make([]int64, 0)
  9. var s3 []int64 = make([]int64, 2)
  10. var s4 []int64 = make([]int64, 4)
  11. fmt.Printf("s1=%d,s2=%d,s3=%d,s4=%d\n", unsafe.Sizeof(s1), unsafe.Sizeof(s2), unsafe.Sizeof(s3), unsafe.Sizeof(s4))
  12. }

__

  1. $ go build && ./main
  2. s1=24,s2=24,s3=24,s4=24

slice数据类型占用24字节,与slice的内容没有关系,因为slice里面存储的是指向真实数据的指针。

slice数据类型的存储格式

前面我们已经看到slice占用空间是24字节,由三个域组成:

__

  1. type struct {
  2. v1 uintptr // 指向真实的数据buffer指针
  3. v2 uint64 // 标记当前slice的len值
  4. v3 uint64 // 标志当前slice的cap值
  5. }

slice类型变量的定义

  • var s1 []int64
    声明一个slice变量,这个slice变量的长度为0,所以不能使用s1[index]来索引,否则会引发错误
    panic: runtime error: index out of range
    但是可以使用s1 = append(s1, 1)

  • var s2 []int64 = make([]int64, 0)
    和前面用法一致,只不过由make执行了初始化工作,初始化工作把s2的v1指针指向一个常量0;而s1没有调用make的初始化,只是执行了变量的初始化,把s1整体初始化成0,从而v1,
    v2, v3也都是0。

  • var s3 []int64 = make([]int64, 2)
    创建一个包含两个元素的slice对象,此时可以使用s3[0]和s3[1]对这两个元素进行初始化。

我们看到s1和s2的变量定义中,他们并没有分配存储空间,也就是说他们的大小为零,因此任何使用s1[index]/s2[index]的方式都是导致下标访问越界。唯一能往里面添加数据是只能是使用append函数
append(s1, 11), append(s2, 22)。

代码

__

  1. package main
  2. import (
  3. "fmt"
  4. "unsafe"
  5. )
  6. type myslice struct {
  7. v1 uintptr
  8. v2 uint64
  9. v3 uint64
  10. }
  11. var p * myslice
  12. func printmemory(p uintptr, size int) {
  13. fmt.Printf("[0x%16x:%2d] =", p, size)
  14. for i := 0; i < size; i++ {
  15. p1 := unsafe.Pointer(p + uintptr(i))
  16. p2 := (*byte)(unsafe.Pointer(p1))
  17. fmt.Printf(" %x", *p2)
  18. }
  19. fmt.Printf("\n")
  20. }
  21. func main() {
  22. var s1 []int64
  23. var s2 []int64 = make([]int64, 0)
  24. var s3 []int64 = make([]int64, 2)
  25. //s1[0] = 0x1234; // panic: runtime error: index out of range
  26. //s2[0] = 0x1234; // panic: runtime error: index out of range
  27. s3[0] = 0x1234;
  28. fmt.Printf("s1=%d,s2=%d,s3=%d\n", len(s1), len(s2), len(s3))
  29. p = (* myslice)(unsafe.Pointer(&s1));
  30. fmt.Printf("p=%p,v1=0x%x,v2=%x,v=%x\n", p, p.v1, p.v2, p.v3)
  31. //printmemory(p.v1, 8)
  32. p = (* myslice)(unsafe.Pointer(&s2));
  33. fmt.Printf("p=%p,v1=0x%x,v2=%x,v=%x\n", p, p.v1, p.v2, p.v3)
  34. printmemory(p.v1, 8)
  35. p = (* myslice)(unsafe.Pointer(&s3));
  36. fmt.Printf("p=%p,v1=0x%x,v2=%x,v=%x\n", p, p.v1, p.v2, p.v3)
  37. printmemory(p.v1, 8)
  38. }

运行结果

__

  1. $ go build && ./main
  2. s1=0,s2=0,s3=2
  3. p=0xc42000a2a0,v1=0x0,v2=0,v=0
  4. p=0xc42000a2c0,v1=0x517cf8,v2=0,v=0
  5. [0x 517cf8: 8] = 0 0 0 0 0 0 0 0
  6. p=0xc42000a2e0,v1=0xc42000e270,v2=2,v=2
  7. [0x c42000e270: 8] = 34 12 0 0 0 0 0 0

可以看到s1和s2的len值都是0,即他们都没有元素空间;s1和s2唯一不同的是s2的v1字段是有一个值0x517cf8,而s1是没有的,是0值;这个值是go常量,指向0。s3的v1指向slice的数据地址,我们看到第一个元素值是0x1234,那是之前s3[0]
= 0x1234设置的。

转载文章,原文链接: go语言slice数据类型的定义和使用

关键字词go数据类型

分享到:

如需留言,请 登录,没有账号?请 注册

0 条评论 0 人参与

顶部 底部