Go语言处理字节切片时,如何避免修改传入参数的底层切片序列?
- 内容介绍
- 文章标签
- 相关推荐
说起Go语言, 很多人第一眼就会想起它的简洁、并发、静态类型,甚至还有那种“写一次跑两次”的神奇感觉。可在实际开发里 一旦把字节切片塞进函数里原本清晰的代码却往往像被调味料浇得一团糟——不小心就会把原数据给改掉,那可是大麻烦,实锤。。
到底为什么切片会“偷懒”地改原数组?
切片本身其实是一段结构体,包含三个字段:指向底层数组的指针、长度以及容量。当我们把一个切片作为参数传递给函数时真正传递进去的是这段结构体的拷贝, 何必呢? 而不是整个底层数组。于是 函数内部对切片元素的写操作,就相当于在共享同一块内存上敲锤子——如果你不小心敲坏了那么别人也能感受到。

案例一:简单赋值导致意外覆盖
func DoSomething { b = 1 },差不多得了...
在调用方:
data := byte{0, 0, 0} DoSomething fmt.Println,没耳听。
图啥呢? 输出: —— 看起来没什么问题, 但如果你之前用data做过其它事情,那可就会被悄悄破坏。
案例二:append导致底层数组换新
func AppendStuff byte { return append }
当原始切片容量不足以容纳新元素时 append 会自动分配一个更大的底层数组,并把旧数据复制过去。此时返回的新切片与原来的指针不同,意味着修改不会影响到调用者,醉了...。
怎么避免这种“暗藏杀手”呢?
最直接的方法就是在函数里先拷贝一份数据,再做任何改动。这样即使内部逻辑有 bug,也不会污染外部世界,切中要害。。
说起Go语言, 很多人第一眼就会想起它的简洁、并发、静态类型,甚至还有那种“写一次跑两次”的神奇感觉。可在实际开发里 一旦把字节切片塞进函数里原本清晰的代码却往往像被调味料浇得一团糟——不小心就会把原数据给改掉,那可是大麻烦,实锤。。
到底为什么切片会“偷懒”地改原数组?
切片本身其实是一段结构体,包含三个字段:指向底层数组的指针、长度以及容量。当我们把一个切片作为参数传递给函数时真正传递进去的是这段结构体的拷贝, 何必呢? 而不是整个底层数组。于是 函数内部对切片元素的写操作,就相当于在共享同一块内存上敲锤子——如果你不小心敲坏了那么别人也能感受到。

案例一:简单赋值导致意外覆盖
func DoSomething { b = 1 },差不多得了...
在调用方:
data := byte{0, 0, 0} DoSomething fmt.Println,没耳听。
图啥呢? 输出: —— 看起来没什么问题, 但如果你之前用data做过其它事情,那可就会被悄悄破坏。
案例二:append导致底层数组换新
func AppendStuff byte { return append }
当原始切片容量不足以容纳新元素时 append 会自动分配一个更大的底层数组,并把旧数据复制过去。此时返回的新切片与原来的指针不同,意味着修改不会影响到调用者,醉了...。
怎么避免这种“暗藏杀手”呢?
最直接的方法就是在函数里先拷贝一份数据,再做任何改动。这样即使内部逻辑有 bug,也不会污染外部世界,切中要害。。

