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 golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to