mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
reflect: add Value.MapRange method and MapIter type
Example of use:
iter := reflect.ValueOf(m).MapRange()
for iter.Next() {
k := iter.Key()
v := iter.Value()
...
}
See issue golang/go#11104
Q. Are there any benchmarks that would exercise the new calls to
copyval in existing code?
Change-Id: Ic469fcab5f1d9d853e76225f89bde01ee1d36e7a
Reviewed-on: https://go-review.googlesource.com/33572
Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
parent
8c0425825c
commit
ede5958385
3 changed files with 215 additions and 17 deletions
|
|
@ -6576,3 +6576,124 @@ func TestIssue22073(t *testing.T) {
|
|||
// Shouldn't panic.
|
||||
m.Call(nil)
|
||||
}
|
||||
|
||||
func TestMapIterNonEmptyMap(t *testing.T) {
|
||||
m := map[string]int{"one": 1, "two": 2, "three": 3}
|
||||
iter := ValueOf(m).MapRange()
|
||||
if got, want := iterateToString(iter), `[one: 1, three: 3, two: 2]`; got != want {
|
||||
t.Errorf("iterator returned %s (after sorting), want %s", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMapIterNilMap(t *testing.T) {
|
||||
var m map[string]int
|
||||
iter := ValueOf(m).MapRange()
|
||||
if got, want := iterateToString(iter), `[]`; got != want {
|
||||
t.Errorf("non-empty result iteratoring nil map: %s", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMapIterSafety(t *testing.T) {
|
||||
// Using a zero MapIter causes a panic, but not a crash.
|
||||
func() {
|
||||
defer func() { recover() }()
|
||||
new(MapIter).Key()
|
||||
t.Fatal("Key did not panic")
|
||||
}()
|
||||
func() {
|
||||
defer func() { recover() }()
|
||||
new(MapIter).Value()
|
||||
t.Fatal("Value did not panic")
|
||||
}()
|
||||
func() {
|
||||
defer func() { recover() }()
|
||||
new(MapIter).Next()
|
||||
t.Fatal("Next did not panic")
|
||||
}()
|
||||
|
||||
// Calling Key/Value on a MapIter before Next
|
||||
// causes a panic, but not a crash.
|
||||
var m map[string]int
|
||||
iter := ValueOf(m).MapRange()
|
||||
|
||||
func() {
|
||||
defer func() { recover() }()
|
||||
iter.Key()
|
||||
t.Fatal("Key did not panic")
|
||||
}()
|
||||
func() {
|
||||
defer func() { recover() }()
|
||||
iter.Value()
|
||||
t.Fatal("Value did not panic")
|
||||
}()
|
||||
|
||||
// Calling Next, Key, or Value on an exhausted iterator
|
||||
// causes a panic, but not a crash.
|
||||
iter.Next() // -> false
|
||||
func() {
|
||||
defer func() { recover() }()
|
||||
iter.Key()
|
||||
t.Fatal("Key did not panic")
|
||||
}()
|
||||
func() {
|
||||
defer func() { recover() }()
|
||||
iter.Value()
|
||||
t.Fatal("Value did not panic")
|
||||
}()
|
||||
func() {
|
||||
defer func() { recover() }()
|
||||
iter.Next()
|
||||
t.Fatal("Next did not panic")
|
||||
}()
|
||||
}
|
||||
|
||||
func TestMapIterNext(t *testing.T) {
|
||||
// The first call to Next should reflect any
|
||||
// insertions to the map since the iterator was created.
|
||||
m := map[string]int{}
|
||||
iter := ValueOf(m).MapRange()
|
||||
m["one"] = 1
|
||||
if got, want := iterateToString(iter), `[one: 1]`; got != want {
|
||||
t.Errorf("iterator returned deleted elements: got %s, want %s", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMapIterDelete0(t *testing.T) {
|
||||
// Delete all elements before first iteration.
|
||||
m := map[string]int{"one": 1, "two": 2, "three": 3}
|
||||
iter := ValueOf(m).MapRange()
|
||||
delete(m, "one")
|
||||
delete(m, "two")
|
||||
delete(m, "three")
|
||||
if got, want := iterateToString(iter), `[]`; got != want {
|
||||
t.Errorf("iterator returned deleted elements: got %s, want %s", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMapIterDelete1(t *testing.T) {
|
||||
// Delete all elements after first iteration.
|
||||
m := map[string]int{"one": 1, "two": 2, "three": 3}
|
||||
iter := ValueOf(m).MapRange()
|
||||
var got []string
|
||||
for iter.Next() {
|
||||
got = append(got, fmt.Sprint(iter.Key(), iter.Value()))
|
||||
delete(m, "one")
|
||||
delete(m, "two")
|
||||
delete(m, "three")
|
||||
}
|
||||
if len(got) != 1 {
|
||||
t.Errorf("iterator returned wrong number of elements: got %d, want 1", len(got))
|
||||
}
|
||||
}
|
||||
|
||||
// iterateToString returns the set of elements
|
||||
// returned by an iterator in readable form.
|
||||
func iterateToString(it *MapIter) string {
|
||||
var got []string
|
||||
for it.Next() {
|
||||
line := fmt.Sprintf("%v: %v", it.Key(), it.Value())
|
||||
got = append(got, line)
|
||||
}
|
||||
sort.Strings(got)
|
||||
return "[" + strings.Join(got, ", ") + "]"
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue