【发布时间】:2016-06-06 01:01:50
【问题描述】:
以下代码在 golang 中实现了 yield 模式。作为一个实验,我正在实现一个all permutations 生成器。但是,当我将切片 A 返回到通道时,如果我不创建数组的新副本,则会得到不正确的结果。
请查看“???”周围的代码。有人可以解释这里的幕后发生了什么吗?我认为由于通道没有缓冲,我保证在将数组的切片发布到通道后,我确保在继续之前会消耗结果。
package main
import (
"fmt"
)
func swap(A []int, i int, j int) {
t := A[i]
A[i] = A[j]
A[j] = t
}
func recurse(A []int, c chan []int, depth int) {
if depth == len(A) {
// ??? Why do I need to copy the data?
// If I do c <- A I get an incorrect answer.
ra := make([]int, len(A))
copy(ra, A)
c <- ra
return
}
for i := depth; i < len(A); i++ {
swap(A, depth, i)
recurse(A, c, depth+1)
swap(A, depth, i)
}
}
func yieldPermutations(A []int, c chan []int) {
recurse(A, c, 0)
close(c)
}
func main() {
A := []int{1, 2, 3}
c2 := make(chan []int)
go yieldPermutations(A, c2)
for v := range c2 {
fmt.Println(v)
}
}
如果我不复制数据,我会得到以下结果:
[1 3 2]
[1 3 2]
[2 3 1]
[2 3 1]
[3 1 2]
[3 1 2]
显然,正确的结果(我们通过数据复制得到)是:
[1 2 3]
[1 3 2]
[2 1 3]
[2 3 1]
[3 2 1]
[3 1 2]
【问题讨论】:
-
A []int不是一个数组,它是一个切片。 -
使用闭包来模拟生成器可能会更好。
-
我最初做了一个闭包,但生成的代码非常复杂——我不愿意在生产中使用。
-
@Volker 已更正,谢谢。
标签: go