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
, int
Dans 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
}
map
S'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