Go中字符串不可变、切片共享底层数组、map需make初始化且非并发安全;字符串用len()得字节长、utf8.RuneCountInString()得字符数;切片append后须接收返回值;map判键存在用v, ok := m[k]。

Go语言中字符串、切片和map是日常开发最频繁使用的三种类型,它们不可互换,但各有清晰的语义和操作边界。掌握其核心方法与常见陷阱,比死记API更重要。
字符串:不可变,但支持高效截取和编码转换
Go中字符串底层是只读字节序列(string本质是结构体:{data *byte, len int}),因此所有“修改”操作都返回新字符串,原值不变。
- 用
len(s)获取字节长度,utf8.RuneCountInString(s)获取真实字符数(处理中文等Unicode时必须用后者) - 索引访问
s[i]得到byte,不是rune;要遍历字符请用for _, r := range s - 子串切片
s[start:end]安全且零分配(只要不越界),例如s[2:5]取第2到第4个字节 - 拼接多个字符串优先用
strings.Builder(比+或fmt.Sprintf更省内存),尤其在循环中
切片:动态数组,共享底层数组需警惕意外修改
切片是引用类型,包含指向底层数组的指针、长度len和容量cap。常见误操作多源于对cap和底层数组共享的理解偏差。
- 创建:用
make([]T, len, cap)控制初始容量;直接字面量[]int{1,2,3}容量等于长度 - 追加元素用
append(s, x)——若容量不足会自动扩容(通常翻倍),返回新切片;原切片变量可能失效,务必接收返回值 - 切片再切片如
s[1:3]会复用原底层数组,修改它可能影响其他引用同一数组的切片;需要隔离时用newS := append([]T(nil), oldS...)深拷贝 - 清空切片推荐
s = s[:0](保留底层数组,适合复用),而非s = nil(释放引用,下次append可能重新分配)
Map:无序哈希表,零值为nil,必须make后才能写入
map是引用类型,但其零值是nil,未初始化就写入会panic。读取不存在的key则返回对应类型的零值,不会报错。
立即学习“go语言免费学习笔记(深入)”;
- 声明后必须
m := make(map[K]V)或m := map[K]V{}初始化;var m map[K]V只是声明nil map - 判断key是否存在:用双赋值
v, ok := m[k],ok为true才表示key存在(避免把零值误判为“有值”) - 删除key用
delete(m, k);清空整个map应遍历+delete,不能直接赋nil(那只是让变量不再指向原map) - map不是并发安全的,多goroutine读写必须加
sync.RWMutex或改用sync.Map(适用于读多写少场景)
字符串重在理解不可变性与Unicode处理,切片关键在掌控底层数组生命周期,map重点在于初始化、存在性检查和并发约束。三者组合使用时(比如用字符串作map键、切片存结构体字段),逻辑就自然清晰了。










