在 Go 编程语言中,数据类型用于声明函数、参数、返回值、定义变量,学习编程语言的基础就是把数据类型的基础理解清楚,本节课精心准备图文对golang数据类型分析(这篇文章是我录制的视频课程里面的一节课件,本着传播知识的精神发出来到博客中)。
1、基础数据类型:
bool型:
bool,值为true或false
整型:
Go 也有基于架构的类型,例如:int、uint 和 uintptr。
uint8 无符号 8 位整型 (0 到 255)、uint16 无符号 16 位整型 (0 到 65535)、uint32 无符号 32 位整型 (0 到 4294967295)、uint64 无符号 64 位整型 (0 到 18446744073709551615)、int8 有符号 8 位整型 (-128 到 127)、int16 有符号 16 位整型 (-32768 到 32767)、int32 有符号 32 位整型 (-2147483648 到 2147483647)、int64 有符号 64 位整型 (-9223372036854775808 到 9223372036854775807)
浮点型:
float32 IEEE-754 32位浮点型数、float64 IEEE-754 64位浮点型数、complex64 32 位实数和虚数、complex128 64 位实数和虚数
派生类型:
var pint *int
var pbool *bool
var c1 chan string
var slice []int64
其他数字类型
byte 类似 uint8、rune 类似 int32、uint 32 或 64 位、int 与 uint 一样大小、uintptr 无符号整型,用于存放一个指针
2、复合数据类型:
数组类型:
数组类型不能动态扩容,其它用法与slice比较相似,其内部结构参照slice类型的结构。
slice类型:
slice由header和body组成。header有3个变量组成:指针、实际数据长度、内存区域最大容量。
举个例子: slice:= make(int[], 4, 6) 创建一个长度为4,容量为6的int类型slice,如下图:
slice在语言包中的定义:
type slice struct {
array unsafe.Pointer
len int
cap int
}
创建切片:
func makeslice(et *_type, len, cap int) slice {
p := mallocgc(et.size*uintptr(cap), et, true)
return slice{p, len, cap}
}
mallocgc
切片扩容:
// slice 扩容伪代码:
{
newcap := old.cap
doublecap := newcap + newcap
if cap > doublecap {
newcap = cap
} else {
if old.len < 1024 {
newcap = doublecap
} else {
for newcap < cap {
newcap += newcap / 4
}
}
}
// 如果容量有扩容,则申请信的内存区域、把旧数据从老的内存区域 copy 到新申请的内存区域、将array 指向新申请的内存区域、标记旧的内存区域可被回收 等待gc回收
}
cap增长的策略:
- 如果期望大于double,新cap就等于期望;
- 如果当前大小小于1024,则两倍增长;
- 否则每次增长25%,直到满足期望。
map类型:
// A header for a Go map.
type hmap struct {
// 元素个数,调用 len(map) 时,直接返回此值
count int
flags uint8
B uint8 // buckets 的对数 log_2
// overflow 的 bucket 近似数
noverflow uint16
// 计算 key 的哈希的时候会传入哈希函数
hash0 uint32
buckets unsafe.Pointer // 指向内存的指针,可以看作是:[]bmap。 其大小为 2^B. 如果元素个数为0,就为 nil
// 扩容的时候,buckets 长度会是 oldbuckets 的两倍
oldbuckets unsafe.Pointer
// 指示扩容进度,小于此地址的 buckets 迁移完成
nevacuate uintptr
extra *mapextra // optional fields
}
// buckets指向的结构体
type bmap struct {
tophash [bucketCnt]uint8 // bucketCnt值固定为8个,也就是每个bmap最大能存储8个key-value对。
}
// go编译器在编译时,会扩展bmap为如下的结构:
type bmap struct {
topbits [8]uint8
keys [8]keytype
values [8]valuetype
pad uintptr
overflow uintptr
}
map结构图:
例如:m1 map[string]string插入一条数据的过程如下:
insert "key1 name":"乔布斯"
hashvalue = hash("key1 name")
slot = hashvalue的低8bit % len(m1),例如m1的槽位是4个,则slot = hashvalue % 4。假设slot = 2
hashvalue的高8bit这条数据应该插入到bmap中的第几个子槽。如果bmap已经写满8个,则读取overflow指向的下一个紧邻着的bmap去插入这条数据
注意:bmap中k-v的存放方式是:key0、key1、key2、key3、key4、key5、key6、key7、val0、val1、val2、val3、val4、val5、val6、val7、pads、overflow (我认为改成叫next更为合适)
结构体:
结构体类型,是基本数据类型和派生类型的组合。与其它编程语言的结构体在组成上面差不多。但是引用与其它有一定的差异,会在interface和对象继承等章节穿插讲。
channel类型:
channel 本质只是一个环形队列,有读、写索引、有互斥锁。 能够及时通知go调度器对读写channel的go routine进行调度。