使用指针的优势
- 节省内存,提高性能(减少数据复制带来的开销)
- 能够直接修改变量的值
- 用于构建链表和树等数据结构
- 优化内存管理管理(将指针设为nil,使对象可被垃圾回收)
值类型和引用类型
- 值类型直接储存值,内存通常在栈上分配
- 引用类型储存的是一个地址,内存通常在堆上分配,通过GC回收
指针和引用的区别
严格来说go没有引用类型,例如map 底层是一个指向 hmap 的指针,这就可以解释即使函数传参是按值传递,由于传递的是指针的拷贝,指针指向的底层 hmap 并没有改变,所以可以在函数内部改变 map
- 引用是变量的别名,通过引用可以直接操控变量本身(快捷方式)
- 指针储存一个内存地址
对象池
内存池
rune和byte有什么区别
类型不同:
- byte:字节,是
uint8的别名类型 - rune:字符,是
int32的别名类型
储存的字符不同:
- byte用于表示ASCII码字符,0-255
- rune用于表示Unicode字符,可以储存任意Unicode字符
占用的字节大小不同
- byte:1
- rune:4
字符串
八位字节集合,可为空,不为nil,本质上是一个byte类型数组,不可变,并发安全,每次修改字符串都需要重新分配内存。之前的空间会被回收。
拼接方式:
var s string
s += "a"
fmt.Sprintf("%s%s", s, "a")
var builder strings.Builder
builder.WriteString("a")
builder.String()
buf := new(bytes.Buffer)
buf.WriteString("a")
buf.String()
baseSlice := []string{"a", "b"}
strings.Join(baseSlice, "")
buf := make([]byte, 0)
base = "a"
buf = append(buf, base...)
string(base)排序: jion = builder > buffer > []byte转换string > + >fmt.sprintf
- builder会预分配空间,减少扩容,效率更高,适合长字符串操作
- buffer主要用于处理单个字符,可以针对单个byte进行删除替换操作
数组和切片的区别
- 数组定长,切片大小可变,自动扩容
- 作为函数参数,数组传值,切片传引用
切片扩容/缩容
- 添加元素容量不足触发扩容,分配一个新的数组,小于1024扩容1倍,大于1024扩容1/4倍
- 删除元素时切片长度小于容量的1/4触发缩容,分配一个新的数组,小于1024长度不变,大于1024缩容1/2。
浅拷贝与深拷贝
- 值类型每次拷贝都会申请一块新的地址
- 引用类型浅拷贝只改变指针的指向(地址),深拷贝会申请一块新的地址
make和new有什么区别
- new给任意类型分配地址,初始化零值,返回指针
- make用于创建并初始化引用类型的变量,如slice、channel,map,返回引用
context
| 场景 | 介绍 |
|---|---|
| 超时处理 | 通过使用 context 可以方便地设置超时时间,在超时后自动终止协程 |
| 终止协程 | 通过使用 cancel() 方法,协程可以很方便地终止 |
| 传递数据 | 我们可以将数据写入 context, 在不同协程间传递数据 |
Map是并发安全的吗
Map不是并发安全
- 手动加读写锁
- 使用sync.Map
Map的key删除后内存会释放吗
- value为值类型,则map的内存不会自动释放
- value为引用类型,则map的内存会自动释放
- map设为nil,内存回收
Map产生的panic能被recover吗
Map 由于并发读写导致的 panic 是不能被 recover 的,因为 Map 的异常使用 runtime.throw() 抛出,这类异常不能被 recover。
泛型和接口有什么区别
- 接口是在运行时实现的,泛型是在编译时实现的,泛型在编译时会编译成具体的类型,所以泛型性能更好
- 接口主要用来约束方法,用于定义对象的行为,泛型主要用来约束类型,让代码可以处理多种类型
- 接口是go语言的原生特性,泛型是1.18版本引入
- 泛型引发的错误在编译时能发现,而接口在运行时才能发现
其它
- 对未初始化的Map赋值会引发panic
- 对未初始化的Map删除会引发Panic(早期版本,现版本不会)
- 对未初始化的Map读取key会返回当前类型的空值
- 执行for range时遍历的时副本
- defer执行顺序先进后出
- Map 会自动扩容,但是不会自动缩容。
- channel 是线程安全的,原因是 channel 内部实现了锁的机制
- Map 在内部使用哈希算法放置元素,在自动扩容时又会重新计算哈希值,因此元素的地址会不断变化,官方为了避免用户认为 Map 元素排列是有序的,直接采用随机顺序返回,所以遍历是无序的