Go语言中什么变量的大小是0字节?数组,字符串,切片底层是一样的吗?

212 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情

什么变量的大小是0字节

  • 使用unsafe.Sizeof 方法可以拿到当前变量的大小

image.png

运行结果为 8 ,经过测试可以发现 int uint 以及 指针 是和系统字长有关系的,在64位系统上的大小是8个字节,在32位系统上是4个字节

  • 空结构体的大小为0

image.png

通过运行会发现空结构体不占用空间没有大小,而且所有空结构体的地址一样

在malloc.go中可以找到 zerobase:所有0字节的地址集合

image.png

  • 注意:只有空结构体独立出现时地址才会是 zerobase

image.png

执行之后会发现 k结构体的地址已经不再是 zerobase 并且大小已经不再是0而是8

空结构体的应用

  • 实现set:只有key 没有 value
  • 通道:发送信号不携带任何信息

image.png

如何正确查看字符串的长度

  • 通过sizeof查看到的是字符串的指针 为16字节
  • 在string.go 下stringStruct 就是string的底层结构

image.png

str 指针指向底层Byte数组

len 表述Byte数组的长度

字符编码问题

  • 所有字符均使用 unicode字符集
  • 使用 UTF-8 编码

Unicode

  • 一种统一的字符集
  • 包括了159种文字的144679个字符
  • 14万个字符至少需要3个字节表示
  • 英文字母均排在前128个

UTF-8

  • Unicode 的一种变长格式
  • 128个 US-ASCii 字符只需一个字节编码
  • 西方常用字符需要两个字节
  • 其他字符需要三个字节,极少需要四个字节

遍历 字符串

image.png

在 utf8.go 中有其实现 range遍历时,被解码成 rune 类型的字符

字符串的切分

  • 需要且分时
    • 转为rune数组
    • 切片
    • 转为string
    • s = string([]rune(s)[:3])

切片

  • 切片的长度都是 24位(64位系统)
  • array 数组的地址,len 切片的长度,cap 切片的容量

image.png

切片的创建

  • 根据数组创建
  • arr[0:3]
  • 字面量:编译时插入创建数组的代码(先创建数组,再创建slice)
  • slice := []int{1,2,3}
  • make:运行时创建数组
  • slice := make([]int,10)

观察通过字面量的方式底层是如何运行的

测试代码

func main() {
   s := []int{6, 7, 8}
   fmt.Println(s)
}

go build -gcflags -S main.go

image.png

  • 在编译时先是创建一个长度为3的int数组
  • 将字面量6,7,8插入到数组中
  • 根据数组创建slice

切片的追加

  • 不扩容时,只调整len(编译器负责)
  • 扩容时,编译时转为调用runtime.growslice()
  • 新建一个数组
  • 如果期望容量大当前容量的2倍,就是使用期望容量
  • 如果当前切片的长度小于1024,将翻倍
  • 如果大于1024,每次增加 25%