Je vais le laisser comme un mémorandum parce que je n'ai pas la capacité de comprendre «refléter».
Je souhaite saisir une valeur spécifique pour une structure dont les éléments de champ sont inconnus.
go playground Ici
J'ai utilisé une fonction récursive.
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
	}
}
reflect.Value est un pointeurAvec ce processus, il est déterminé si le champ est un pointeur, et s'il est "nil", "reflct.Value" est généré. Si ce n'est pas «nil», utilisez le premier argument de la fonction récursive tel quel. Passez la référence du pointeur au premier argument de la fonction récursive et appelez-le à nouveau. Après l'appel, si «CanSet» est «true», définissez «Value» sur «Set» comme premier argument.
	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
	}
reflect.Value est une structureÉnumérez les champs de la structure, passez chaque champ comme premier argument de la fonction récursive et appelez-le à nouveau.
Cependant, le cas de PkgPath (package) et le cas de Anonymous (type embarqué) sont exclus (il y a un cas de boucle permanente si non exclue).
	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
	}
reflect.Value est string, intDans le cas de "string", il est converti, et dans le cas de "int", il est "Set" with "reflect.ValueOf" tel quel.
(Puisqu'il existe des cas autres que string et int, nous cherchons à savoir si cela peut être simplifié un peu plus ...)
	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 et imprimer les données manquantesConvertir de map [string] string en une structure arbitraire, et s'il n'y a pas assez d'éléments dans les champs de la structure, j'aimerais connaître les détails.
Spécifiez une balise pour le champ de la structure et si le champ est du côté du pointeur, traitez-le comme facultatif.
De plus, en faisant du premier argument du type bindParameters une interface, il correspond à n'importe quelle structure.
go playground Ici
Modifié en fonction de la fonction récursive de [here](#corresponding 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, ""
}
Vous pouvez obtenir le nom de balise de la structure avec reflect.StructField.sf.Tag.Get.
	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
	}
mapS'il ne peut pas être extrait, «paramètre n'est pas spécifié», s'il ne peut pas être converti en «chaîne», «valeur non numérique» est remplacé par «retour». (Nous étudions un style d'écriture un peu plus intelligent, y compris comment gérer d'autres types ...)
	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, ""
	}
Je veux également considérer le cas où «-» et «omitempty» peuvent être spécifiés dans la balise.
Recommended Posts