Ich lasse es als Memorandum, weil mir die Fähigkeit fehlt, "reflektieren" zu verstehen.
Ich möchte einen bestimmten Wert für eine Struktur eingeben, deren Feldelemente unbekannt sind.
go playground Hier
Ich habe eine rekursive Funktion verwendet.
func recursive(in reflect.Value, v int) {
rt := in.Kind()
if rt == reflect.Ptr {
vPtr := in
if in.IsNil() {
vPtr = reflect.New(in.Type().Elem())
}
recursive(vPtr.Elem(), v)
if in.CanSet() {
in.Set(vPtr)
}
return
}
if rt == reflect.Struct {
tValue := in.Type()
for i := 0; i < in.NumField(); i++ {
sf := tValue.Field(i)
if sf.PkgPath != "" && !sf.Anonymous {
continue
}
recursive(in.Field(i), v)
}
return
}
if rt == reflect.String {
strV := strconv.Itoa(v)
in.Set(reflect.ValueOf(strV))
return
}
if rt == reflect.Int {
in.Set(reflect.ValueOf(v))
return
}
}
Mit diesem Prozess wird bestimmt, ob das Feld ein Zeiger ist, und wenn es "null" ist, wird "reflct.Value" generiert. Wenn es nicht "Null" ist, verwenden Sie das erste Argument der rekursiven Funktion so wie es ist. Übergeben Sie die Zeigerreferenz an das erste Argument der rekursiven Funktion und rufen Sie sie erneut auf. Wenn nach dem Aufruf "CanSet" "true" ist, setzen Sie "Value" als erstes Argument auf "Set".
if rt == reflect.Ptr {
vPtr := in
if in.IsNil() {
vPtr = reflect.New(in.Type().Elem())
}
recursive(vPtr.Elem(), v)
if in.CanSet() {
in.Set(vPtr)
}
return
}
Zählen Sie die Felder der Struktur auf, übergeben Sie jedes Feld als erstes Argument der rekursiven Funktion und rufen Sie es erneut auf. Der Fall von "PkgPath" (Paket) und der Fall von "Anonymous" (eingebetteter Typ) werden jedoch ausgeschlossen (es gibt einen Fall einer permanenten Schleife, wenn nicht ausgeschlossen).
if rt == reflect.Struct {
tValue := in.Type()
for i := 0; i < in.NumField(); i++ {
sf := tValue.Field(i)
if sf.PkgPath != "" && !sf.Anonymous {
continue
}
recursive(in.Field(i), v)
}
return
}
Im Fall von "string" wird es konvertiert, und im Fall von "int" wird es mit "Reflect.ValueOf" so wie es ist "Set". (Da es andere Fälle als "string" und "int" gibt, untersuchen wir, ob dies etwas weiter vereinfacht werden kann ...)
if rt == reflect.String {
strV := strconv.Itoa(v)
in.Set(reflect.ValueOf(strV))
return
}
if rt == reflect.Int {
in.Set(reflect.ValueOf(v))
return
}
map
zu füllen und fehlende Daten auszudruckenKonvertieren Sie von "map [string] string" in eine beliebige Struktur, und wenn die Felder der Struktur nicht genügend Elemente enthalten, möchte ich die Details wissen. Geben Sie ein Tag für das Feld der Struktur an. Wenn sich das Feld auf der Zeigerseite befindet, behandeln Sie es als optional. Wenn Sie das erste Argument vom Typ "bindParameters" als "Schnittstelle" festlegen, entspricht es einer beliebigen Struktur.
go playground Hier
Geändert basierend auf der rekursiven Funktion von [hier](# entsprechender Code).
func recursive(in reflect.Value, tag string, required bool, v map[string]string, res *map[string]interface{}) bool {
rk := in.Kind()
if rk == reflect.Ptr {
vPtr := in
if in.IsNil() {
vPtr = reflect.New(in.Type().Elem())
}
isSet := recursive(vPtr.Elem(), tag, false, v, res)
if in.CanSet() && isSet {
in.Set(vPtr)
}
return false
}
if rk == reflect.Struct {
tValue := in.Type()
isSet := false
for i := 0; i < in.NumField(); i++ {
sf := tValue.Field(i)
if sf.PkgPath != "" && !sf.Anonymous {
continue
}
tagName := ""
required = false
if uriTag := sf.Tag.Get(key); uriTag != "" {
tagName = uriTag
required = true
}
r := recursive(in.Field(i), tagName, required, v, res)
if r {
isSet = true
}
}
return isSet
}
ptrValue, errString := getValue(rk, required, tag, v)
if errString != "" {
e := *res
e[tag] = errString
res = &e
}
if ptrValue != nil {
value := *ptrValue
in.Set(value)
return true
}
return false
}
func getValue(kind reflect.Kind, required bool, tag string, m map[string]string) (*reflect.Value, string) {
var value string
var ok bool
if value, ok = m[tag]; !ok && required {
return nil, "parameter is not specified"
}
if value == "" && !required {
return nil, ""
}
if kind == reflect.String {
r := reflect.ValueOf(value)
return &r, ""
}
if kind == reflect.Int {
i, err := strconv.Atoi(value)
if err != nil {
return nil, "not numeric value"
}
r := reflect.ValueOf(i)
return &r, ""
}
return nil, ""
}
Sie können den Tag-Namen der Struktur mit reflektieren.StructField.sf.Tag.Get
erhalten.
if rk == reflect.Struct {
tValue := in.Type()
isSet := false
for i := 0; i < in.NumField(); i++ {
sf := tValue.Field(i)
if sf.PkgPath != "" && !sf.Anonymous {
continue
}
tagName := ""
required = false
if uriTag := sf.Tag.Get(key); uriTag != "" {
tagName = uriTag
required = true
}
r := recursive(in.Field(i), tagName, required, v, res)
if r {
isSet = true
}
}
return isSet
}
map
Wenn es nicht extrahiert werden kann, wird "Parameter nicht angegeben", wenn es nicht in "Zeichenfolge" konvertiert werden kann, wird "nicht numerischer Wert" in "Rückgabe" geändert. (Wir untersuchen einen etwas intelligenteren Schreibstil, einschließlich des Umgangs mit anderen Typen ...)
if value, ok = m[tag]; !ok && required {
return nil, "parameter is not specified"
}
if value == "" && !required {
return nil, ""
}
if kind == reflect.String {
r := reflect.ValueOf(value)
return &r, ""
}
if kind == reflect.Int {
i, err := strconv.Atoi(value)
if err != nil {
return nil, "not numeric value"
}
r := reflect.ValueOf(i)
return &r, ""
}
Ich möchte auch den Fall betrachten, in dem -
und omitempty
im Tag angegeben werden können.
Recommended Posts