golang slice [:]与最后一个元素匹配

I am working on a sample program in golang which is as follows

package main

import (
    "fmt"
)

type thing [2]byte

func walk(things []thing, idx int) []byte {
    var match []byte
    for i, thing := range things {
        if i == idx {
            match = thing[:]
        }
    }
    return match
}


func main() {
    ta := []thing{ thing{'W','A'}, thing{'O','R'} }
    m := walk(ta, 0)

    tb := []thing{ thing{'C','A'}, thing{'W','Y'}, thing{'N','V'} }
    n := walk(tb, 1)

    fmt.Printf("m = %s
", m)
    fmt.Printf("n = %s
", n)
}

The output is:

m = OR
n = NV

I am not sure why this is the case when type thing [2]byte is an array of size 2 and ta is type []thing.

Now when you write the same code as this using [][]byte

package main

import (
    "fmt"
)

func walk(things [][]byte, idx int) []byte {
    var match []byte
    for i, thing := range things {
        if i == idx {
            match = thing[:]
        }
    }
    return match
}

func main() {
    ta := [][]byte{[]byte{'W', 'A'}, []byte{'O', 'R'}}
    m := walk(ta, 0)

    tb := [][]byte{[]byte{'C', 'A'}, []byte{'W', 'Y'}, []byte{'N', 'V'}}
    n := walk(tb, 1)

    fmt.Printf("m = %s
", m)
    fmt.Printf("n = %s
", n)
}

The output is

m = WA
n = WY

I am confused by these different behaviours of slices? Printing out ta[:] when ta is type thing []byte and ta[:] when ta is [][]byte is the same

Two cases are not the same.

In the first case, you are working with [][2]byte (slice of arrays) not with [][]byte (slice of slices).

var match []byte
for i, thing := range things { // (2) change array on each iteration
    fmt.Printf("Thing %v", thing)
    if i == idx {
        match = thing[:] // (1) slice refers to array   
    }
}
return match // (3) here match slice refers to the last item of things

One of solutions here is adding break statement after match = thing[:]. It ends the loop and match will refer to expected array.

Just to clarify what is the actual issue here, the problem is that you are creating an slice that refers to an array that is overwritted in each n-iteration with the values of the correspondant n-th element of the slice of 2 bytes array. So if you don't stop iterating the slice will get the values of the last element.

Using a for .. := range "hides" a little bit this fact. I guess if you write the same code with a for i;i<n;i++, you could get a better understanding of what is actually happening: https://play.golang.org/p/z3hCskZ9ezV

In one case, an individual thing is an array ([2]byte), and in the other, it's a slice ([]byte). In the first case, you're slicing an array into match, which gives you a new slice pointing at your loop iteration variable. In the second case, you're re-slicing an existing slice, so your new slice points at that slice's underlying array, even after the loop changes out the local slice variable.

Because your loop keeps running after you find your match, you find your match, slice it, then keep iterating, changing the value of the local loop iterator. If you did:

    if i == idx {
        return thing[:]
    }

instead, the issue disappears: https://play.golang.org/p/Uq4DbEGlGX8