Go语言核心(二)

基本数据类型
  • 空结构体
type struct K {}
1. int 大小跟随系统长度 
2. 指针大小也是跟随系统长度 指针类型在wind64 是8个字节
type struct K {} -- K 是空结构体 zerobase 所有的地址相同
3. a:=K{} 空结构体的字节长度为0 ,但是有地址, 
b: = int(0); c:=K{} , 发现 空结构体指向的同一个地址,go语言中这个称作为zerobase (是所有长度为0的地址)

空结构体的主要作用是节约内存, 不使用 就不是节约,为啥还会有空结构体?
4. 在没有值只有key的 map
5. 空channel: a:=make(chan struct{}) 负责传递空结构体过去 但是不会占用内存, 只是进行标识通道是通的
  • 数组,字符串,数组切片底层一样?
6. unsafe.SizeOf("moock") == unsafe.SizeOf("moock网络") == 16 ?
   为什么字符串的长度是16个字节长度, 主要字符串本质是结果体, 存放的是指针,所以发现SizeOf后,求的是指针地址长度因此长度都是16个字节, 指针指向的Byte数组, 使用反射包里面StringHeader 查看stringStruct 中
   s := "慕课王"
   sh := (*reflect.StringHeader)(unsafe.Pointer(&s)) // utf-8 输出为9
从这了解到 Len 表示的是Byte 数组长度 不是字符串长度,主要原因是编码问题
Go语言使用Unicode 字符集,使用 utf-8(边长编码) 进行编码表示至少需要3个字节,注意英文字母均排在128, 纯英文使用一个字节

由于字符串属于变长编码,不能使用 for index 方式,输出的是底层字节,使用foreach 方式 for _,char in range s
切分:s = string([]rune(s)[:3])

go 语言 Map
runtime.hmap 属于go 语言的 map, 使用拉链方法
B : 桶的数量log_2, count: map 数量, buckets 跟随 bmap 数组
bmap (tohash, keys,elems, overflow) 只能放8个数据,所有的key 放到一起

---------------------
map 初始化:
 m := make(map[string]int, 10)
 通过字面量初始化: 定义初始化, 元素少于 25 直接填充,元素多于 25 创建两个数组,直接赋值进入
---------------------
对于死循环 建议使用 select, 不能并发的进行map的读写
* A协程在桶中读数据, B 协程驱逐这个桶,导致数据竞争问题
* 使用 sync.Map 的数据结构, 类似与ConcurrentHashMap
* 空接口指代任何数据类型
Sync.Map 中 read.map, dirty.map ,dirty.Map 用来处理追加的 追加主要扩容,如果需要新key 需要扩容 通过mu 锁住 dirty.map 同时 misses ++ 表示没有命中,当 misses 如如果命中次数 = len(dirty) 后, 直接将 dirty.map 进行提权

属于 普通的读写和追加分离,所以对于Sync.map 删除 分为 正常删除和追加删除,删除都不是删除key, 或者将value 强制 nil, sync.map 使用map ,sync.map 特别适用于 读写多但是追加少场景
接口
  • 一个接口值在底层是怎么样?
1. 接口数据使用 runtime.iface 表示
2. iface 记录数据的地址
3. iface 也记录接口类型信息和实现方法 (主要是做类型断言) t:=c.(Truck), 如果一个结构体 实现不同接口内部的相同方法名称方法 使用上述方式进行转换, 一个结构体可以实现不同接口的同名方法
  • 结果体和结构体指针
    如果使用结构体实体实现一个方法时候,Go 编译器会帮你在多实现一个结构体指针的方法,反之不会,属于一个单向
    结构体多实现一个结果体指针的数据
  • 空接口
    空接口可以表示任何数据, 属于runtime.eface 的底层数据结构
  1. 作用作为方法入参,可以支持任何数据类型
// 比如在我们使用Println
func Println(a ...interface{})(n int, err error){
}

nil, 空结构体,空接口区别

  1. nil 是空,并不一定是空指针, 属于 6种类型的零值,不能表示空结构体
var nil Type // Type may be pointer, channel, func, interface 初始
var a *int// 表示一个空指针
var b map[int][int] 
var c struct {} // nil 不能表示 空结构体

  1. 空结构体
    空结构体的值不是nil, 空结构体指针也不是nil,有相同的zerobase

  2. 空接口
    1- 空接口不一定是nil
    2- 空接口一旦被赋值之后,不在是nil

	var a interface{}
	var c *int
	a = c
	fmt.Println(c == nil)
	fmt.Println(a == nil) // 空接口被赋值 后 不是 nil false

内存对齐

1. 为什么两个结构体 字节大小相同?
非内存对齐, 导致CPU访问频繁,所以采用内存对齐的,放在一个CPU的字长效率中,提高内存操作效率有利于内存原子性;
go 语言提供了 对齐系数, unsafe.Aligonof(), 第一个字节地址被 对齐系数给整除

type S1 struct {
	num1 int32
	num2 int32
}

type S2 struct {
	num1 int16
	num2 int32
}

func main() {
	fmt.Println(unsafe.Sizeof(S1{})) // 8
	fmt.Println(unsafe.Sizeof(S2{})) // 8
}
  1. 结构体对齐
  2. 内部对齐: 结构体内部的成员相对位置,偏移量 是自身大小和对齐系数较小值的 倍数
  3. 结构体的对齐系数属于最大结构体的对齐系数
  4. 空结构体出现在结构体末尾时,需要补齐字长,会紧随前一个变量, 所以空结构体最好放到中间
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值