Skip to content

Commit 524a774

Browse files
qiulaidongfenggopherbot
authored andcommitted
reflect: add iterative related methods
Fixes #66056 Change-Id: I1e24636e43e68cd57576c39b014e0826fb6c322c GitHub-Last-Rev: 319ad8e GitHub-Pull-Request: #66824 Reviewed-on: https://go-review.googlesource.com/c/go/+/578815 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]> Reviewed-by: Cherry Mui <[email protected]>
1 parent 49eedfb commit 524a774

File tree

6 files changed

+540
-0
lines changed

6 files changed

+540
-0
lines changed

api/next/66056.txt

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
pkg reflect, method (Value) Seq() iter.Seq[Value] #66056
2+
pkg reflect, method (Value) Seq2() iter.Seq2[Value, Value] #66056
3+
pkg reflect, type Type interface, CanSeq() bool #66056
4+
pkg reflect, type Type interface, CanSeq2() bool #66056
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
The new methods [Value.Seq] and [Value.Seq2] return sequences that iterate over the value
2+
as though it were used in a for/range loop.
3+
The new methods [Type.CanSeq] and [Type.CanSeq2] report whether calling
4+
[Value.Seq] and [Value.Seq2], respectively, will succeed without panicking.

src/reflect/iter.go

+140
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
// Copyright 2024 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package reflect
6+
7+
import "iter"
8+
9+
// Seq returns an iter.Seq[reflect.Value] that loops over the elements of v.
10+
// If v's kind is Func, it must be a function that has no results and
11+
// that takes a single argument of type func(T) bool for some type T.
12+
// If v's kind is Pointer, the pointer element type must have kind Array.
13+
// Otherwise v's kind must be Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr,
14+
// Array, Chan, Map, Slice, or String.
15+
func (v Value) Seq() iter.Seq[Value] {
16+
if canRangeFunc(v.typ()) {
17+
return func(yield func(Value) bool) {
18+
rf := MakeFunc(v.Type().In(0), func(in []Value) []Value {
19+
return []Value{ValueOf(yield(in[0]))}
20+
})
21+
v.Call([]Value{rf})
22+
}
23+
}
24+
switch v.Kind() {
25+
case Int, Int8, Int16, Int32, Int64:
26+
return func(yield func(Value) bool) {
27+
for i := range v.Int() {
28+
if !yield(ValueOf(i)) {
29+
return
30+
}
31+
}
32+
}
33+
case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr:
34+
return func(yield func(Value) bool) {
35+
for i := range v.Uint() {
36+
if !yield(ValueOf(i)) {
37+
return
38+
}
39+
}
40+
}
41+
case Pointer:
42+
if v.Elem().kind() != Array {
43+
break
44+
}
45+
return func(yield func(Value) bool) {
46+
v = v.Elem()
47+
for i := range v.Len() {
48+
if !yield(ValueOf(i)) {
49+
return
50+
}
51+
}
52+
}
53+
case Array, Slice:
54+
return func(yield func(Value) bool) {
55+
for i := range v.Len() {
56+
if !yield(ValueOf(i)) {
57+
return
58+
}
59+
}
60+
}
61+
case String:
62+
return func(yield func(Value) bool) {
63+
for i := range v.String() {
64+
if !yield(ValueOf(i)) {
65+
return
66+
}
67+
}
68+
}
69+
case Map:
70+
return func(yield func(Value) bool) {
71+
i := v.MapRange()
72+
for i.Next() {
73+
if !yield(i.Key()) {
74+
return
75+
}
76+
}
77+
}
78+
case Chan:
79+
return func(yield func(Value) bool) {
80+
for value, ok := v.Recv(); ok; value, ok = v.Recv() {
81+
if !yield(value) {
82+
return
83+
}
84+
}
85+
}
86+
}
87+
panic("reflect: " + v.Type().String() + " cannot produce iter.Seq[Value]")
88+
}
89+
90+
// Seq2 is like Seq but for two values.
91+
func (v Value) Seq2() iter.Seq2[Value, Value] {
92+
if canRangeFunc2(v.typ()) {
93+
return func(yield func(Value, Value) bool) {
94+
rf := MakeFunc(v.Type().In(0), func(in []Value) []Value {
95+
return []Value{ValueOf(yield(in[0], in[1]))}
96+
})
97+
v.Call([]Value{rf})
98+
}
99+
}
100+
switch v.Kind() {
101+
case Pointer:
102+
if v.Elem().kind() != Array {
103+
break
104+
}
105+
return func(yield func(Value, Value) bool) {
106+
v = v.Elem()
107+
for i := range v.Len() {
108+
if !yield(ValueOf(i), v.Index(i)) {
109+
return
110+
}
111+
}
112+
}
113+
case Array, Slice:
114+
return func(yield func(Value, Value) bool) {
115+
for i := range v.Len() {
116+
if !yield(ValueOf(i), v.Index(i)) {
117+
return
118+
}
119+
}
120+
}
121+
case String:
122+
return func(yield func(Value, Value) bool) {
123+
for i, v := range v.String() {
124+
if !yield(ValueOf(i), ValueOf(v)) {
125+
return
126+
}
127+
}
128+
}
129+
case Map:
130+
return func(yield func(Value, Value) bool) {
131+
i := v.MapRange()
132+
for i.Next() {
133+
if !yield(i.Key(), i.Value()) {
134+
return
135+
}
136+
}
137+
}
138+
}
139+
panic("reflect: " + v.Type().String() + " cannot produce iter.Seq2[Value, Value]")
140+
}

0 commit comments

Comments
 (0)