Golang语言社区go学习代码世界

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

2017-09-05  本文已影响11人  CodingCode

这篇文章介绍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类型变量的定义

我们看到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设置的。

上一篇下一篇

猜你喜欢

热点阅读