Dies und das mit reflektieren

Zweck

Ich lasse es als Memorandum, weil mir die Fähigkeit fehlt, "reflektieren" zu verstehen.

Verwenden Sie Reflect, um die Felder der Struktur zu füllen

Tor

Ich möchte einen bestimmten Wert für eine Struktur eingeben, deren Feldelemente unbekannt sind.

go playground Hier

Hauptverarbeitung

Entsprechender Code

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
	}
}

Überblick über die Verarbeitung

Wenn der Typ von "Reflect.Value" ein Zeiger ist

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
	}
Wenn der Typ von "Reflect.Value" eine Struktur ist

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
	}
Wenn der Typ von "Reflect.Value" "String" ist, "Int"

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
	}

Verwenden Sie Reflect, um die Strukturfelder aus map zu füllen und fehlende Daten auszudrucken

Tor

Konvertieren 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

Hauptverarbeitung

Entsprechender Code

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, ""
}

Überblick über die Verarbeitung

Struktur-Tag-Analyse

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
	}
Extrahieren Sie den dem Tag entsprechenden Wert aus 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, ""
	}

Andere

Ich möchte auch den Fall betrachten, in dem - und omitempty im Tag angegeben werden können.

Recommended Posts

Dies und das mit reflektieren
Dies und das mit NLTK (Memo)
matplotlib dies und das
Dies und das über pd.DataFrame
Zabbix API dies und das
Dies und das haben wir von boost.python gelernt
Dies und das von Python-Eigenschaften
Dies und das der Einschlussnotation.
Dies und das ist nützlich, wenn es mit nohup verwendet wird
Dies und das um MySQL in der Apache-Umgebung (Hinweis)
Bei Verwendung von if und bei Verwendung von while
Versuchen Sie es mit pytest-Overview und Samples-
Authentifizierung mit Tweepy-User-Authentifizierung und Anwendungsauthentifizierung (Python)
Senden Sie Nachrichten und Bilder mit LineNotify
Vorsichtsmaßnahmen bei der Verwendung von Codecs und Pandas
Hinweise zur Verwendung von Post-Receive und Post-Merge
Multithread-Zundokokiyoshi mit Event und Queue
Verwenden von Sitzungen und Reflexionen mit SQL Alchemy
Clustering und Visualisierung mit Python und CytoScape
Einfaches und einfaches IoT-Leben mit Micropython!
Backtrace mit DWARF-Informationen und Pyelftools