reflect: add missing iterator methods

This commit is contained in:
Jake Bailey
2026-07-05 23:03:56 -07:00
committed by Ron Evans
parent 7c3dc05117
commit f1fdfe2313
3 changed files with 120 additions and 0 deletions
+25
View File
@@ -8,6 +8,31 @@ import (
"iter"
)
// Fields returns an iterator over each StructField of v along with its Value.
func (v Value) Fields() iter.Seq2[StructField, Value] {
if v.Kind() != Struct {
panic(&ValueError{Method: "reflect.Value.Fields", Kind: v.Kind()})
}
return func(yield func(StructField, Value) bool) {
for i, n := 0, v.NumField(); i < n; i++ {
if !yield(v.Type().Field(i), v.Field(i)) {
return
}
}
}
}
// Methods returns an iterator over each Method of v along with its Value.
func (v Value) Methods() iter.Seq2[Method, Value] {
return func(yield func(Method, Value) bool) {
for i, n := 0, v.NumMethod(); i < n; i++ {
if !yield(v.Type().Method(i), v.Method(i)) {
return
}
}
}
}
func rangeNum[T int8 | int16 | int32 | int64 | int |
uint8 | uint16 | uint32 | uint64 | uint |
uintptr, N int64 | uint64](num N, t Type) iter.Seq[Value] {
+39
View File
@@ -383,6 +383,45 @@ func TestValueSeq2(t *testing.T) {
}
}
func TestValueFields(t *testing.T) {
type T struct {
First int
Second string
Third bool
}
v := ValueOf(T{First: 10, Second: "visible", Third: true})
names := []string{"First", "Second", "Third"}
values := []any{10, "visible", true}
var count int
for field, value := range v.Fields() {
if field.Name != names[count] {
t.Fatalf("field %d name = %q, want %q", count, field.Name, names[count])
}
if field.Index[0] != count {
t.Fatalf("field %d index = %v, want [%d]", count, field.Index, count)
}
if got := value.Interface(); got != values[count] {
t.Fatalf("field %d value = %v, want %v", count, got, values[count])
}
count++
}
if count != len(names) {
t.Fatalf("field count = %d, want %d", count, len(names))
}
count = 0
for field := range v.Type().Fields() {
if field.Name != names[count] {
t.Fatalf("type field %d name = %q, want %q", count, field.Name, names[count])
}
count++
}
if count != len(names) {
t.Fatalf("type field count = %d, want %d", count, len(names))
}
}
// methodIter is a type from which we can derive a method
// value that is an iter.Seq.
type methodIter struct{}
+56
View File
@@ -65,6 +65,7 @@ package reflect
import (
"internal/reflectlite"
"iter"
"unsafe"
)
@@ -265,6 +266,10 @@ type Type interface {
// It panics if i is not in the range [0, NumField()).
Field(i int) StructField
// Fields returns an iterator over each struct field for struct type t.
// It panics if the type's Kind is not Struct.
Fields() iter.Seq[StructField]
// FieldByIndex returns the nested field corresponding
// to the index sequence. It is equivalent to calling Field
// successively for each index i.
@@ -294,6 +299,10 @@ type Type interface {
// It panics if i is not in the range [0, NumIn()).
In(i int) Type
// Ins returns an iterator over each input parameter of function type t.
// It panics if the type's Kind is not Func.
Ins() iter.Seq[Type]
// Key returns a map type's key type.
// It panics if the type's Kind is not Map.
Key() Type
@@ -319,6 +328,10 @@ type Type interface {
// It panics if i is not in the range [0, NumOut()).
Out(i int) Type
// Outs returns an iterator over each output parameter of function type t.
// It panics if the type's Kind is not Func.
Outs() iter.Seq[Type]
// OverflowComplex reports whether the complex128 x cannot be represented by type t.
// It panics if t's Kind is not Complex64 or Complex128.
OverflowComplex(x complex128) bool
@@ -340,6 +353,9 @@ type Type interface {
// CanSeq2 reports whether a [Value] with this type can be iterated over using [Value.Seq2].
CanSeq2() bool
// Methods returns an iterator over each method in the type's method set.
Methods() iter.Seq[Method]
}
type rawType struct {
@@ -414,6 +430,16 @@ func (t *rawType) Field(i int) StructField {
return toStructField(f)
}
func (t *rawType) Fields() iter.Seq[StructField] {
return func(yield func(StructField) bool) {
for i, n := 0, t.NumField(); i < n; i++ {
if !yield(t.Field(i)) {
return
}
}
}
}
func (t *rawType) FieldByIndex(index []int) StructField {
f := t.RawType.FieldByIndex(index)
return toStructField(f)
@@ -437,6 +463,16 @@ func (t *rawType) In(i int) Type {
panic("unimplemented: (reflect.Type).In()")
}
func (t *rawType) Ins() iter.Seq[Type] {
return func(yield func(Type) bool) {
for i, n := 0, t.NumIn(); i < n; i++ {
if !yield(t.In(i)) {
return
}
}
}
}
func (t *rawType) IsVariadic() bool {
panic("unimplemented: (reflect.Type).IsVariadic()")
}
@@ -453,6 +489,16 @@ func (t *rawType) MethodByName(name string) (Method, bool) {
panic("unimplemented: (reflect.Type).MethodByName()")
}
func (t *rawType) Methods() iter.Seq[Method] {
return func(yield func(Method) bool) {
for i, n := 0, t.NumMethod(); i < n; i++ {
if !yield(t.Method(i)) {
return
}
}
}
}
func (t *rawType) NumIn() int {
panic("unimplemented: (reflect.Type).NumIn()")
}
@@ -465,6 +511,16 @@ func (t *rawType) Out(i int) Type {
panic("unimplemented: (reflect.Type).Out()")
}
func (t *rawType) Outs() iter.Seq[Type] {
return func(yield func(Type) bool) {
for i, n := 0, t.NumOut(); i < n; i++ {
if !yield(t.Out(i)) {
return
}
}
}
}
// A StructField describes a single field in a struct.
// This must be kept in sync with [reflectlite.StructField].
type StructField struct {