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.

Reply via email to