Skip to content

Commit 6b5ba32

Browse files
committed
reflect: add iterator equivalents for NumField, NumIn, NumOut and NumMethod
The new methods are Type.Fields, Type.Methods, Type.Ins, Type.Outs, Value.Fields and Value.Methods. Fixes #66631 address comments fix the obvious case
1 parent 34e6762 commit 6b5ba32

File tree

3 files changed

+105
-0
lines changed

3 files changed

+105
-0
lines changed

api/next/66631.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pkg reflect, type Type interface, Fields() iter.Seq[StructField] #66631
2+
pkg reflect, type Type interface, Methods() iter.Seq[Method] #66631
3+
pkg reflect, type Type interface, Ins() iter.Seq[Type] #66631
4+
pkg reflect, type Type interface, Outs() iter.Seq[Type] #66631
5+
pkg reflect, method (Value) Fields() iter.Seq2[StructField, Value] #66631
6+
pkg reflect, method (Value) Methods() iter.Seq2[Method, Value] #66631

src/reflect/type.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package reflect
1818
import (
1919
"internal/abi"
2020
"internal/goarch"
21+
"iter"
2122
"runtime"
2223
"strconv"
2324
"sync"
@@ -255,6 +256,22 @@ type Type interface {
255256
// CanSeq2 reports whether a [Value] with this type can be iterated over using [Value.Seq2].
256257
CanSeq2() bool
257258

259+
// Fields yields each field of a struct type.
260+
// It panics if the type's Kind is not Struct.
261+
Fields() iter.Seq[StructField]
262+
263+
// Methods yields each method in the type's method set.
264+
// See [Type.Method] for information on the yielded methods.
265+
Methods() iter.Seq[Method]
266+
267+
// Ins yields each input parameter of a function type, in order.
268+
// It panics if the type's Kind is not Func.
269+
Ins() iter.Seq[Type]
270+
271+
// Outs yields each output parameter of a function type, in order.
272+
// It panics if the type's Kind is not Func.
273+
Outs() iter.Seq[Type]
274+
258275
common() *abi.Type
259276
uncommon() *uncommonType
260277
}
@@ -934,6 +951,46 @@ func canRangeFunc2(t *abi.Type) bool {
934951
return yield.InCount == 2 && yield.OutCount == 1 && yield.Out(0).Kind() == abi.Bool
935952
}
936953

954+
func (t *rtype) Fields() iter.Seq[StructField] {
955+
return func(yield func(StructField) bool) {
956+
for i := range t.NumField() {
957+
if !yield(t.Field(i)) {
958+
return
959+
}
960+
}
961+
}
962+
}
963+
964+
func (t *rtype) Methods() iter.Seq[Method] {
965+
return func(yield func(Method) bool) {
966+
for i := range t.NumMethod() {
967+
if !yield(t.Method(i)) {
968+
return
969+
}
970+
}
971+
}
972+
}
973+
974+
func (t *rtype) Ins() iter.Seq[Type] {
975+
return func(yield func(Type) bool) {
976+
for i := range t.NumIn() {
977+
if !yield(t.In(i)) {
978+
return
979+
}
980+
}
981+
}
982+
}
983+
984+
func (t *rtype) Outs() iter.Seq[Type] {
985+
return func(yield func(Type) bool) {
986+
for i := range t.NumOut() {
987+
if !yield(t.Out(i)) {
988+
return
989+
}
990+
}
991+
}
992+
}
993+
937994
// add returns p+x.
938995
//
939996
// The whySafe string is ignored, so that the function still inlines

src/reflect/value.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"internal/goarch"
1111
"internal/itoa"
1212
"internal/unsafeheader"
13+
"iter"
1314
"math"
1415
"runtime"
1516
"unsafe"
@@ -2620,6 +2621,47 @@ func (v Value) UnsafePointer() unsafe.Pointer {
26202621
panic(&ValueError{"reflect.Value.UnsafePointer", v.kind()})
26212622
}
26222623

2624+
// Fields yields each field of v, along with its description.
2625+
//
2626+
// It panics if v's Kind is not Struct.
2627+
//
2628+
// The i'th field yielded by Fields is the same as [Type.Field(i)] and [Value.Field(i)].
2629+
func (v Value) Fields() iter.Seq2[StructField, Value] {
2630+
return func(yield func(StructField, Value) bool) {
2631+
rtype := v.Type()
2632+
for i := range v.NumField() {
2633+
if !yield(rtype.Field(i), v.Field(i)) {
2634+
return
2635+
}
2636+
}
2637+
}
2638+
}
2639+
2640+
// Methods yields a function value corresponding to each method of v,
2641+
// along with a description of the method.
2642+
//
2643+
// The arguments to a Call on the yielded function value should not include a receiver;
2644+
// the returned function will always use v as the receiver. Note that [Method.Type]
2645+
// in each yielded [Method] does include the receiver, and thus is not the same as
2646+
// [Value.Type].
2647+
//
2648+
// Methods panics if v is a nil interface value.
2649+
//
2650+
// The i'th method yielded by Methods is the same as [Type.Method(i)] and [Value.Method(i)].
2651+
//
2652+
// Calling this method will force the linker to retain all exported methods in all packages.
2653+
// This may make the executable binary larger but will not affect execution time.
2654+
func (v Value) Methods() iter.Seq2[Method, Value] {
2655+
return func(yield func(Method, Value) bool) {
2656+
rtype := v.Type()
2657+
for i := range v.NumMethod() {
2658+
if !yield(rtype.Method(i), v.Method(i)) {
2659+
return
2660+
}
2661+
}
2662+
}
2663+
}
2664+
26232665
// StringHeader is the runtime representation of a string.
26242666
// It cannot be used safely or portably and its representation may
26252667
// change in a later release.

0 commit comments

Comments
 (0)