I try to implement Python-style generator with a channel following this:
package main
import (
"fmt"
)
type ContainerIterable[T any] struct {
content []T
}
func NewContainerIterable[T any]() *ContainerIterable[T] {
return &ContainerIterable[T]{content: make([]T, 0)}
}
func (c *ContainerIterable[T]) Iterate() chan T {
ch := make(chan T)
go func() {
for _, v := range c.content {
ch <- v
}
close(ch)
}()
return ch
}
func (c *ContainerIterable[T]) Add(e T) {
c.content = append(c.content, e)
}
func main() {
c := NewContainerIterable[int]()
for i := 0; i < 5; i++ {
c.Add(i)
}
r := make([]int, 0)
for v := range c.Iterate() {
r = append(r, v)
}
for i := 0; i < 5; i++ {
fmt.Println(i, r[i], i == r[i])
}
}
This works just fine and the output is
0 0 true
1 1 true
2 2 true
3 3 true
4 4 true
However, when I change
r := make([]int, 0)
to
r := make([]int, 5)
the result is different:
0 0 true
1 0 false
2 0 false
3 0 false
4 0 false
I understand that in the second case c.Iterate()
starts reading from channel before
go func() {
for _, v := range c.content {
ch <- v
}
has a chance to send anything to channel.
This does not apply to the first case since main()
goroutine takes some time to reallocate space for r
slice when append()
is invoked.
Please advise how to adjust my code to make Iterate()
work properly?
This:
r := make([]int, 5)
will initialize a slice that has 5 elements, all 0. Then you'll add 5 elements more to it. Your program is reading the first 5 zero elements.
Use: r:=make([]int,0,5)