我正在研究golang中的示例程序,如下所示
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\n", m)
fmt.Printf("n = %s\n", n)
}
输出结果为:
m = OR
n = NV
我不知道为什么会出现这种情况,因为type thing [2] byte是一个大小为2的数组,而ta是类型[]的东西。
现在使用[] [] 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\n", m)
fmt.Printf("n = %s\n", n)
}
输出
m = WA
n = WY
我对这些不同的切片行为感到困惑?
当ta[:]
和ta is type thing []byte
相同时打印ta[:] when ta is [][]byte
答案 0 :(得分:2)
在一种情况下,个人thing
是一个数组([2]byte
),而在另一种情况下,它是一个切片([]byte
)。在第一种情况下,您将数组切片为match
,这会为您提供一个指向循环迭代变量的新切片。在第二种情况下,您将重新切片现有切片,因此即使在循环更改了局部切片变量之后,您的新切片也会指向该切片的基础数组。
因为你的循环在你找到你的匹配后继续运行,你找到你的匹配,切片,然后继续迭代,改变本地循环迭代器的值。如果你这样做了:
if i == idx {
return thing[:]
}
答案 1 :(得分:2)
两种情况 不 相同。
在第一种情况中,您使用的是[][2]byte
(数组切片),而不是[][]byte
(切片切片)。
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
此处的解决方案之一是在break
之后添加match = thing[:]
语句。它结束循环,match
将引用预期的数组。
为了澄清这里的实际问题,问题是您正在创建一个切片,该切片引用在每个 n-iteration 中被覆盖的数组,其中包含对应的 2字节数组切片的第n个元素。 因此,如果您不停止迭代,切片将获得最后一个元素的值。
使用for .. := range
“隐藏”这个事实。我想如果你用for i;i<n;i++
编写相同的代码,你可以更好地理解实际发生的事情:https://play.golang.org/p/z3hCskZ9ezV