附加到 2d 切片时的奇怪行为

Strange behavior when appending to a 2d slice

我正在使用 2D 字节切片来表示一堆行,但是当我附加到其中一行时,我得到了一些非常奇怪的行为。

这是一个例子:

package main

import (
    "bytes"
    "fmt"
)

func main() {
    str := []byte("first line\nsecond line\nthird line")
    values := bytes.Split(str, []byte("\n"))

    fmt.Println("Before:")
    fmt.Println(string(values[0]))
    fmt.Println(string(values[1]))
    fmt.Println(string(values[2]))
    fmt.Println()

    values[0] = append(values[0], []byte("-inserted text-")...)

    fmt.Println("After:")
    fmt.Println(string(values[0]))
    fmt.Println(string(values[1]))
    fmt.Println(string(values[2]))
}

我希望这个程序的输出是

Before:
first line
second line
third line

After:
first line-inserted text-
second line
third line

但输出是:

Before:
first line
second line
third line

After:
first line-inserted text-
inserted te
t-ird line

https://play.golang.org/p/iNw6s1S66U

为什么会发生这种情况,我该如何解决?

有趣的是,如果我不使用拆分而是像这样定义值,就不会发生这种情况:

values := [][]byte{[]byte("first line"), []byte("second line"), []byte("third line")}

https://play.golang.org/p/pEflrhKLd4

您所做的是附加到字符串,而不是附加到数组,这会溢出切片的底层数据结构。这就是数组的其余部分被您附加的字符串覆盖的原因。

澄清一下(情况可能并非总是如此):

数组values由连续排列的3个[]字节块组成。每个 []byte 块都有固定长度(基于其中字符串的长度)。所以 values[0] 的长度为 10(不包括 '\n' 或 '\0')。现在,如果您尝试将 "-inserted text-" 附加到该块,字符将 "flow" 进入连续的块 values[1],将 values[1] 中的字符替换为 [= 中的字符12=]。这就是为什么您会在 values[1]values[1].

中看到这些字符的一部分

底层存储是共享的,因此要获得您想要的效果,您需要存储从 bytes.Split 返回的切片的副本,而不仅仅是返回的切片。当您追加到返回的第一个切片时,您实际上是在踩踏所有后续切片。