慕工程0101907
joshlf 给出了一个很好的答案,但我想补充几点:使用渠道通道迭代器的一个典型问题是你必须遍历整个数据结构,否则提供通道的 goroutine 将永远挂起。但这很容易绕过,这是一种方法:func (s intSlice) chanIter() chan int { c := make(chan int) go func() { for _, i := range s { select { case c <- i: case <-c: close(c) return } } close(c) }() return c}在这种情况下,写回迭代器通道会提前中断迭代:s := intSlice{1, 2, 3, 4, 5, 11, 22, 33, 44, 55}c := s.chanIter()for i := range c { fmt.Println(i) if i > 30 { // Send to c to interrupt c <- 0 }}在这里,不要简单地break跳出 for 循环,这一点非常重要。您可以中断,但必须先写入通道以确保 goroutine 退出。使用闭包我经常倾向于使用的一种迭代方法是使用迭代器闭包。在这种情况下,迭代器是一个函数值,当重复调用时,它返回下一个元素并指示迭代是否可以继续:func (s intSlice) cloIter() func() (int, bool) { i := -1 return func() (int, bool) { i++ if i == len(s) { return 0, false } return s[i], true }}像这样使用它:iter := s.cloIter()for i, ok := iter(); ok; i, ok = iter() { fmt.Println(i)}在这种情况下,尽早跳出循环是完全可以的,iter最终会被垃圾收集。操场这是上述实现的链接:http : //play.golang.org/p/JC2EpBDQKA