学习一门语言最重要的就是搞清变量和内存的对应关系
Variables are the names given to a memory location where the actual data is stored。
Go数据类型分类
Go数据类型根据零值的不同可以分成普通类型和泛指针类型两大类。泛指针类型的零值是nil
普通类型包括:布尔型、整型、浮点型、字符串、数组
泛指针类型包括:指针、slice、map、channel、function、interface
什么是零值?
当变量被声明,但是没有初始化的时候,(变量被声明的时候,就被分配了内存空间),Golang会根据变量类型在分配的内存里放一个默认值,这个默认值就是Zero Value
.
什么是元数据metadata
metadata就是数据的数据。例如一个整型变量是一个数据,它的地址就是它的元数据,所以指针就是一个元数据,
Metadata is simply data about data. It means it is a description and context of the data. It helps to organize, find and understand data.
Go 变量声明(Declaration)
Go中声明一个变量,就会在内存中分配空间来存储这个变量的数据,变量对应着的就是这块内存。
对于普通类型,这块申请的空间存储的就是我们要处理的数据;而对于泛指针类型,这块内存空间存储的是我们要处理的数据的元数据(metadata)
,我们通过这个元数据来访问我们想要处理的数据。
所有的泛指针类型的元数据都包含指向我们想要处理的数据的指针。例如:pointer里面存储的就是我们要处理的数据的地址;slice的元数据里面有我们要处理的底层数组的地址;map的元数据里有底层哈希表的地址。
例子:
当声明了一个slice, 会在内存中分配空间来存放slice的元数据:一个指向底层数组的指针、切片长度len、切片容量cap。
可以将slice看成是下面的结构:
type slice struct{
ptr *Elem //指向底层数组的指针
len int
cap int
}
当泛指针类型仅仅进行了声明,而没有初始化时,这是仅仅分配了存储元数据的内存空间,我们要处理的数据的内存空间没有分配(或者尚未和元数据建立关系)。
没有指向底层数组的slice
只能进行appped来写数据(append函数内部会新建底层数组), 不能通过index写数据;没有指向底层哈希表的map不能够写数据。
需要使用new
函数或者make
函数来分配底层存储结构的内存。new
函数返回的申请的空间的地址,make
函数返回的是指定类型的实例。
变量赋值
变量赋值包括函数调用过程中的赋值,函数调用相当于用实参给形参赋值。Golang必须是类型一模一样的变量才可以互相赋值。
Golang中所有类型的变量赋值都是值传递。只不过由于泛指针类型的变量赋值只是复制了元数据,这样两个变量所使用的底层数据仍是一样的,所以看起来像是引用传递。
普通类型的变量赋值就是将内存中的数据完全复制一份作为被赋值变量的数据;泛指针变量的赋值是将变量对应的元数据完全复制一份作为被赋值变量的元数据,底层的数据不变。