附加到二维切片时的奇怪行为

I am using a 2D slice of bytes to represent a bunch of lines, but when I append to one of the lines, I get some very strange behavior.

Here is an example:

package main

import (
    "bytes"
    "fmt"
)

func main() {
    str := []byte("first line
second line
third line")
    values := bytes.Split(str, []byte("
"))

    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]))
}

I would expect the output of this program to be

Before:
first line
second line
third line

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

But instead the output is:

Before:
first line
second line
third line

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

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

Why is this happening and how can I fix it?

Interestingly, this doesn't happen if I don't use split and instead define values like so:

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

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

The underlying storage is shared, so to get the effect you want, you would need to store copies of the slices returned from bytes.Split, rather than just the slices returned. When you append to the first slice returned, you're essentially stomping all over the following slices.

What you're doing is appending to the string, instead of appending to the array and thats overflowing the underlying data structure for the slice. Which is why the rest of the array is overwritten with the string you're appending.

To clarify (this may not always be the case):

the array values consists of 3 []byte blocks lined up consecutively. Each []byte block has a fixed length (based on the length of the string within it). So values[0] has a length of 10 (excluding ' ' or '\0'). Now if you try to append "-inserted text-" to that block, the characters will "flow" over into the consecutive block, values[1], replacing the characters within values[1] with the characters in "-inserted text-". That's why you see parts of those characters within values[1] and values[1].