美文网首页Golang语言社区go学习代码世界
go语言slice数据类型的定义和使用

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

作者: CodingCode | 来源:发表于2017-09-05 14:59 被阅读11次

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

    slice数据类型大小

    package main
    
    import (
        "fmt"
        "unsafe"
    )
    
    func main() {
      var s1 []int64
      var s2 []int64 = make([]int64, 0)
      var s3 []int64 = make([]int64, 2)
      var s4 []int64 = make([]int64, 4)
    
      fmt.Printf("s1=%d,s2=%d,s3=%d,s4=%d\n", unsafe.Sizeof(s1), unsafe.Sizeof(s2), unsafe.Sizeof(s3), unsafe.Sizeof(s4))
    
    }
    
    $ go build && ./main 
    s1=24,s2=24,s3=24,s4=24
    

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

    slice数据类型的存储格式

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

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

    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)。

    代码

    package main
    
    import (
        "fmt"
        "unsafe"
    )
    
    type myslice struct {
        v1 uintptr
        v2 uint64
        v3 uint64
    }
    
    var p * myslice
    
    func printmemory(p uintptr, size int) {
        fmt.Printf("[0x%16x:%2d] =", p, size)
        for i := 0; i < size; i++ {
            p1 := unsafe.Pointer(p + uintptr(i))
            p2 := (*byte)(unsafe.Pointer(p1))
            fmt.Printf(" %x", *p2)
        }
        fmt.Printf("\n")
    }
    
    func main() {
      var s1 []int64
      var s2 []int64 = make([]int64, 0)
      var s3 []int64 = make([]int64, 2)
      
      //s1[0] = 0x1234;    // panic: runtime error: index out of range
      //s2[0] = 0x1234;    // panic: runtime error: index out of range
      s3[0] = 0x1234;
      fmt.Printf("s1=%d,s2=%d,s3=%d\n", len(s1), len(s2), len(s3))
    
      p = (* myslice)(unsafe.Pointer(&s1));
      fmt.Printf("p=%p,v1=0x%x,v2=%x,v=%x\n", p, p.v1, p.v2, p.v3)
      //printmemory(p.v1, 8)
    
      p = (* myslice)(unsafe.Pointer(&s2));
      fmt.Printf("p=%p,v1=0x%x,v2=%x,v=%x\n", p, p.v1, p.v2, p.v3)
      printmemory(p.v1, 8)
    
      p = (* myslice)(unsafe.Pointer(&s3));
      fmt.Printf("p=%p,v1=0x%x,v2=%x,v=%x\n", p, p.v1, p.v2, p.v3)
      printmemory(p.v1, 8)
    }
    

    运行结果

    $ go build && ./main 
    s1=0,s2=0,s3=2
    p=0xc42000a2a0,v1=0x0,v2=0,v=0
    p=0xc42000a2c0,v1=0x517cf8,v2=0,v=0
    [0x          517cf8: 8] = 0 0 0 0 0 0 0 0
    p=0xc42000a2e0,v1=0xc42000e270,v2=2,v=2
    [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数据类型的定义和使用

        本文链接:https://www.haomeiwen.com/subject/wavujxtx.html