reflect: Add FieldByNameFunc
This adds FieldByNameFunc, which some libraries like reflect2 need. For my usecase I could also just stub FieldByNameFunc to panic, but figured that it would work OK to just make it work. I'm not sure if the overhead to FieldByName using a closure is acceptable. Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
Этот коммит содержится в:
родитель
dd4e9e86e7
коммит
fdc4bbbfad
3 изменённых файлов: 48 добавлений и 5 удалений
|
@ -360,7 +360,7 @@ type Type interface {
|
|||
// and FieldByNameFunc returns no match.
|
||||
// This behavior mirrors Go's handling of name lookup in
|
||||
// structs containing embedded fields.
|
||||
//FieldByNameFunc(match func(string) bool) (StructField, bool)
|
||||
FieldByNameFunc(match func(string) bool) (StructField, bool)
|
||||
|
||||
// In returns the type of a function type's i'th input parameter.
|
||||
// It panics if the type's Kind is not Func.
|
||||
|
@ -722,11 +722,11 @@ func (t *rawType) rawField(n int) rawStructField {
|
|||
return rawStructFieldFromPointer(descriptor, field.fieldType, data, flagsByte, name, offset)
|
||||
}
|
||||
|
||||
// rawFieldByName returns nearly the same value as FieldByName but without converting the
|
||||
// rawFieldByNameFunc returns nearly the same value as FieldByNameFunc but without converting the
|
||||
// Type member to an interface.
|
||||
//
|
||||
// For internal use only.
|
||||
func (t *rawType) rawFieldByName(n string) (rawStructField, []int, bool) {
|
||||
func (t *rawType) rawFieldByNameFunc(match func(string) bool) (rawStructField, []int, bool) {
|
||||
if t.Kind() != Struct {
|
||||
panic(errTypeField)
|
||||
}
|
||||
|
@ -769,7 +769,7 @@ func (t *rawType) rawFieldByName(n string) (rawStructField, []int, bool) {
|
|||
|
||||
name := readStringZ(data)
|
||||
data = unsafe.Add(data, len(name))
|
||||
if name == n {
|
||||
if match(name) {
|
||||
found = append(found, result{
|
||||
rawStructFieldFromPointer(descriptor, field.fieldType, data, flagsByte, name, offset),
|
||||
append(ll.index, int(i)),
|
||||
|
@ -1099,7 +1099,28 @@ func (t *rawType) FieldByName(name string) (StructField, bool) {
|
|||
panic(errTypeFieldByName)
|
||||
}
|
||||
|
||||
field, index, ok := t.rawFieldByName(name)
|
||||
field, index, ok := t.rawFieldByNameFunc(func(n string) bool { return n == name })
|
||||
if !ok {
|
||||
return StructField{}, false
|
||||
}
|
||||
|
||||
return StructField{
|
||||
Name: field.Name,
|
||||
PkgPath: field.PkgPath,
|
||||
Type: field.Type, // note: converts rawType to Type
|
||||
Tag: field.Tag,
|
||||
Anonymous: field.Anonymous,
|
||||
Offset: field.Offset,
|
||||
Index: index,
|
||||
}, true
|
||||
}
|
||||
|
||||
func (t *rawType) FieldByNameFunc(match func(string) bool) (StructField, bool) {
|
||||
if t.Kind() != Struct {
|
||||
panic(TypeError{"FieldByNameFunc"})
|
||||
}
|
||||
|
||||
field, index, ok := t.rawFieldByNameFunc(match)
|
||||
if !ok {
|
||||
return StructField{}, false
|
||||
}
|
||||
|
|
|
@ -1846,6 +1846,17 @@ func (v Value) FieldByName(name string) Value {
|
|||
return Value{}
|
||||
}
|
||||
|
||||
func (v Value) FieldByNameFunc(match func(string) bool) Value {
|
||||
if v.Kind() != Struct {
|
||||
panic(&ValueError{"FieldByName", v.Kind()})
|
||||
}
|
||||
|
||||
if field, ok := v.typecode.FieldByNameFunc(match); ok {
|
||||
return v.FieldByIndex(field.Index)
|
||||
}
|
||||
return Value{}
|
||||
}
|
||||
|
||||
//go:linkname hashmapMake runtime.hashmapMakeUnsafePointer
|
||||
func hashmapMake(keySize, valueSize uintptr, sizeHint uintptr, alg uint8) unsafe.Pointer
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"encoding/base64"
|
||||
. "reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -452,10 +453,20 @@ func TestTinyStruct(t *testing.T) {
|
|||
t.Errorf("StrucTag for Foo=%v, want %v", got, want)
|
||||
}
|
||||
|
||||
q, ok = reffb.FieldByNameFunc(func(s string) bool { return strings.ToLower(s) == "bar" })
|
||||
if q.Name != "Bar" || !ok {
|
||||
t.Errorf("FieldByNameFunc(bar)=%v,%v, want Bar, true", q.Name, ok)
|
||||
}
|
||||
|
||||
q, ok = reffb.FieldByName("Snorble")
|
||||
if q.Name != "" || ok {
|
||||
t.Errorf("FieldByName(Snorble)=%v,%v, want ``, false", q.Name, ok)
|
||||
}
|
||||
|
||||
q, ok = reffb.FieldByNameFunc(func(s string) bool { return strings.ToLower(s) == "snorble" })
|
||||
if q.Name != "" || ok {
|
||||
t.Errorf("FieldByName(snorble)=%v,%v, want ``, false", q.Name, ok)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTinyZero(t *testing.T) {
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче