嵌套的字符串字段无法使用反射在任意的Go结构体中进行更新。

huangapple go评论85阅读模式
英文:

Nested string fields can not be updated using reflection in an arbitrary Go struct

问题

我正在尝试使用反射在Go语言中更新结构体及其子字段的所有字符串字段。以下是一个示例代码:

package main

import (
	"fmt"
	"reflect"
	"strings"
)

func main() {
	type Inner struct {
		In1 string
		In2 []string
	}

	type Type struct {
		Name  string
		Names []string
		NewSt Inner
	}

	a := Type{
		Name:  " [(Amir[ ",
		Names: nil,
		NewSt: Inner{
			In1: " [in1",
			In2: []string{"  [in2( "},
		},
	}

	trims(&a)
	fmt.Printf("%#v\n", a)
}

func trim(str string) string {
	return strings.TrimSpace(strings.Trim(str, "[](){}, "))
}

func trims(ps interface{}) {
	v := reflect.ValueOf(ps).Elem() // Elem() dereferences pointer
	for i := 0; i < v.NumField(); i++ {
		fv := v.Field(i)
		switch fv.Kind() {
		case reflect.String:
			fv.SetString(trim(fv.String()))
		case reflect.Struct:
			in := fv.Addr().Interface()
			trims(in)
		}
	}
}

但是我遇到了panic: reflect: call of reflect.Value.Elem on struct Value错误。我该如何修复它,或者是否有更好的方法可以实现这样的功能?

谢谢。

英文:

I'm trying to update all string fields in a struct and its subfields using reflection in golang for an arbitrary struct as follows:

package main
import (
    &quot;fmt&quot;
    &quot;reflect&quot;
    &quot;strings&quot;
)

func main() {
    type Inner struct {
	    In1 string
	    In2 []string
    }

    type Type struct {
	    Name  string
	    Names []string
	    NewSt Inner
    }

    a := Type{
	    Name:  &quot; [ (Amir[ &quot;,
	    Names: nil,
	    NewSt: Inner{
		    In1: &quot; [in1&quot;,
		    In2: []string{&quot;  [in2( &quot;},
	    },
    }

    trims(&amp;a)
    fmt.Printf(&quot;%#v\n&quot;, a)
}

func trim(str string) string {
	return strings.TrimSpace(strings.Trim(str, &quot;[](){}, &quot;))
}

func trims(ps interface{}) {
    v := reflect.ValueOf(ps).Elem() // Elem() dereferences pointer
    for i := 0; i &lt; v.NumField(); i++ {
	    fv := v.Field(i)
	    switch fv.Kind() {
	    case reflect.String:
		    fv.SetString(trim(fv.String()))
	    case reflect.Struct:
    		in := fv.Interface()
    		trims(&amp;in)
    	}
    }
}

But I get panic: reflect: call of reflect.Value.Elem on struct Value error.
How can I fix it or is there any better way that I can do such thing??

Thanks.

答案1

得分: 0

func trims(ps interface{}) {
	v := reflect.ValueOf(ps)
	if v.Kind() == reflect.Ptr {
		v = v.Elem() // Elem()解引用指针
	}
	if v.Kind() != reflect.Struct {
		panic("不是结构体")
	}
	for i := 0; i < v.NumField(); i++ {
		fv := v.Field(i)
		switch fv.Kind() {
		case reflect.String:
			fv.SetString(strings.TrimSpace(fv.String()))
		case reflect.Struct:
			// 使用Addr()获取字段的可寻址值
			in := fv.Addr().Interface()

			// 不要使用&amp;in,它会评估为*interface{},这几乎永远不是你想要的
			trims(in)
		case reflect.Slice:
			if fv.Type().Elem().Kind() == reflect.String {
				for i := 0; i < fv.Len(); i++ {
					fv.Index(i).SetString(strings.TrimSpace(fv.Index(i).String()))
				}
			}
		}
	}
}

https://go.dev/play/p/JkJTJzTckNA

英文:
func trims(ps interface{}) {
	v := reflect.ValueOf(ps)
	if v.Kind() == reflect.Ptr {
		v = v.Elem() // Elem() dereferences pointer
	}
	if v.Kind() != reflect.Struct {
		panic(&quot;not struct&quot;)
	}
	for i := 0; i &lt; v.NumField(); i++ {
		fv := v.Field(i)
		switch fv.Kind() {
		case reflect.String:
			fv.SetString(trim(fv.String()))
		case reflect.Struct:
            // use Addr() to get an addressable
            // value of the field
			in := fv.Addr().Interface()

            // do not use &amp;in, that evaluates
            // to *interface{}, that&#39;s almost
            // NEVER what you want
			trims(in)
        case reflect.Slice:
			if fv.Type().Elem().Kind() == reflect.String {
				for i := 0; i &lt; fv.Len(); i++ {
					fv.Index(i).SetString(trim(fv.Index(i).String()))
				}
			}
		}
	}
}

https://go.dev/play/p/JkJTJzTckNA

huangapple
  • 本文由 发表于 2022年3月1日 19:08:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/71307535.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定