Yes, a Close would, but that adds an API knob that shouln't be needed.
The closure approach is the first option that I posted.
On Fri, 2018-08-03 at 09:39 +0200, Sebastien Binet wrote:
> wouldn't this prevent the goroutine leak, w/o the need to drain the
> channel?
>
> func iterator(m map[KT]VT) iter {
> itr := iter{C: make(chan VT), quit: make(chan struct{})}
> go func() {
> for _, v := range m {
> select {
> case <-itr.quit:
> return
> case itr.C <- v:
> }
> }
> close(i)
> }()
> return i
> }
>
> func (itr *iter) Close() { close(itr.quit) }
>
> that won't address the performance issue, of course.
>
> that said, perhaps you could turn it around and have the iteration
> process
> take a closure, pretty much like path/filepath.Walk ?
>
> -s
>
>
> On Fri, Aug 3, 2018 at 12:29 AM Dan Kortschak <dan.kortschak@adelaide
> .edu.au>
> wrote:
>
> >
> > Go lacks a nice way to hand around a map iteration state. There are
> > ways to to this, but they either require handing around a doubly-
> > wrapped closure
> >
> > ```
> > func iterator(m map[KT]VT) func(func(v VT)) {
> > return func(fn func (v VT)) {
> > for _, v := range m {
> > fn(v)
> > }
> > }
> > }
> > ```
> >
> > which does not allow real pausable iteration without additional
> > callback horror making is essentially useless for public API (where
> > this is actually useful).
> >
> > A goroutine based system
> >
> > ```
> > type iter <-chan VT
> >
> > func (i iter) next() (VT, bool) {
> > v, ok := <-i
> > return v, ok
> > }
> >
> > func iterator(m map[KT]VT) iter {
> > i := make(chan VT)
> > go func() {
> > for _, v := range m {
> > i <- v
> > }
> > close(i)
> > }()
> > return i
> > }
> > ```
> >
> > which requires that the user must drain to complete map or cause a
> > goroutine leak and has significant performance impacts still.
> >
> > Or to copy out all the keys and then iterate over them
> >
> > ```
> > type iter struct {
> > m map[KT]VT
> > idx int
> > keys []KT
> > }
> >
> > func (i *iter) next() (VT, bool) {
> > if i.idx < len(i.keys) {
> >
> > v, ok := i.m[i.keys[i.idx]]
> > i.idx++
> > return v, ok
> > }
> > var v VT
> > return v, false
> > }
> >
> > func iterator(m map[KT]VT) *iter {
> > i := iter{m: m, keys: make([]KT, 0, len(m))}
> > for k := range m {
> > i.keys = append(i.keys, k)
> > }
> > return &i
> > }
> > ```
> >
> > Which may result in significant additional work and allocation and
> > is
> > fundamentally not lazy.
> >
> >
> > However, there is an iterator state type in runtime that is made
> > use of in
> > reflect in the Value.MapKeys method. At the moment this is iterated
> > over in
> > a single pass allocating a []reflect.Value that is intended to be
> > used in a
> > call to Value.MapIndex in a manner analogous to the last example
> > above.
> >
> > Is there a good reason not to provide a map iteration type in
> > reflect to
> > allow users to avoid that eager work. This would be a closer
> > (though not
> > identical as is always the case with reflect) approximation to the
> > language's actual range operator.
> >
> > For example (signatures only)
> >
> > ```
> > type MapRange struct {...
> >
> > func (r *MapRange) Next() bool
> >
> > func (r *MapRange) Value() Value
> >
> > func (v Value) MapRange() *MapRange
> > ```
> >
> > thanks
> > Dan
> >
> > --
> > You received this message because you are subscribed to the Google
> > Groups
> > "golang-nuts" group.
> > To unsubscribe from this group and stop receiving emails from it,
> > send an
> > email to [email protected].
> > For more options, visit https://groups.google.com/d/optout.
> >
--
You received this message because you are subscribed to the Google Groups
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.