使用反射迭代结构体中的切片结构体。

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

Iterating slice struct within struct using reflection

问题

我正在尝试实现以下内容:

使用案例:

  • 我有三个结构体,我需要将其中的两个与另一个进行比较(在示例中描述为:需要将a和b与full进行比较)。
  • 使用反射循环遍历每个字段,获取字段的名称。并比较a和full、b和full之间的差异,将结果存储在一个共享结构体中。
  • 如果字段等于"World",我们知道它是一个切片结构体:
    • 我需要获取Foo结构体中Bar切片的第一个索引。
    • 即使变量是一个切片,我知道在这个案例中它的长度始终为1。
    • 获取后,我需要像前一个if语句中所发生的那样循环遍历这些字段。

示例代码:

  1. type Foo struct {
  2. Hello string
  3. World []Bar
  4. }
  5. type Bar struct {
  6. Fish string
  7. }
  8. type Result struct {
  9. Field string
  10. Correct_A bool
  11. Distance_A int
  12. Correct_B bool
  13. Distance_B int
  14. Result []Result
  15. }
  16. func compare_structs() {
  17. var full, a, b Foo
  18. // 填充所有变量...
  19. result := []Result{}
  20. rfx_f := reflect.ValueOf(full)
  21. rfx_a := reflect.ValueOf(a)
  22. rfx_b := reflect.ValueOf(b)
  23. type_result := rfx_f.Type()
  24. for i := 0; i < rfx_f.NumField(); i++ {
  25. tmp_res := Result{
  26. Field: type_result.Field(i).Name,
  27. }
  28. if reflect.TypeOf(full).Field(i).Type.Kind() != reflect.Slice {
  29. value := rfx_f.Field(i).Interface()
  30. value_a := rfx_a.FieldByName(tmp_res.Field).Interface()
  31. value_b := rfx_b.FieldByName(tmp_res.Field).Interface()
  32. // 比较该字段的值的函数
  33. tmp_res.compare(value, value_a, value_b)
  34. tmp_res.lev(value, value_a, value_b)
  35. result = append(result, tmp_res)
  36. } else if tmp_res.Field == "World" {
  37. /*
  38. 我需要获取Foo结构体中Bar切片的第一个索引。
  39. 即使变量是一个切片,我知道在这个案例中它的长度始终为1。
  40. 获取后,我需要像前一个if语句中所发生的那样循环遍历这些字段。
  41. */
  42. }
  43. }
  44. }
英文:

I'm trying to achieve the following:

Use-case:

  • I have three structures, I need to compare 2 of those against one. (in the example described as: a & b need to be compared against full)
  • Reflection is used to loop over every field, retrieve the name of the field. And comparing the difference between a & full, b & full, storing the results in a shared structure.
  • If the field equals World, we know it's a slice struct:
    I need to retrieve the first index of the Bar slice within the Foo structure.
    Even though the variable is a slice, I know it will always have a length of 1 in this use-case.
    When retrieved I need to loop over those fields, like what is happening in the previous if statement.

Example code:

  1. type Foo struct {
  2. Hello string
  3. World []Bar
  4. }
  5. type Bar struct {
  6. Fish string
  7. }
  8. type Result struct {
  9. Field string
  10. Correct_A bool
  11. Distance_A int
  12. Correct_B bool
  13. Distance_B int
  14. Result []Result
  15. }
  16. func compare_structs() {
  17. var full, a, b Foo
  18. // filling in all variables...
  19. result := []Result{}
  20. rfx_f := reflect.ValueOf(full)
  21. rfx_a := reflect.ValueOf(a)
  22. rfx_b := reflect.ValueOf(b)
  23. type_result := rfx_f.Type()
  24. for i := 0; i &lt; rfx_f.NumField(); i++ {
  25. tmp_res := Result{
  26. Field: type_result.Field(i).Name,
  27. }
  28. if reflect.TypeOf(full).Field(i).Type.Kind() != reflect.Slice {
  29. value := rfx_f.Field(i).Interface()
  30. value_a := rfx_a.FieldByName(tmp_res.Field).Interface()
  31. value_b := rfx_b.FieldByName(tmp_res.Field).Interface()
  32. // functions to compare the values of this field
  33. tmp_res.compare(value, value_a, value_b)
  34. tmp_res.lev(value, value_a, value_b)
  35. result = append(result, tmp_res)
  36. } else if tmp_res.Field == &quot;World&quot; {
  37. /*
  38. I need to retrieve the first index of the Bar slice within the Foo structure.
  39. Even though the variable is a slice, I know it will always have a length of 1 in this use-case.
  40. When retrieved I need to loop over those fields, like what is happening in the previous if statement.
  41. */
  42. }
  43. }
  44. }

答案1

得分: 1

你首先需要获取字段:

  1. wordField := rfx_f.Field(i)

你知道它是一个切片,所以你可以通过索引来获取第一个元素:

  1. item := wordField.Index(0)

如果索引超出范围,这将引发 panic。

然后你可以迭代字段:

  1. for fieldIx := 0; fieldIx < item.NumField(); fieldIx++ {
  2. field := item.Field(fieldIx)
  3. }
英文:

You first need to get the field:

  1. wordField:=rfx_f.Field(i)

which you know to be a slice, so you index it to get the first element

  1. item:=wordField.Index(0)

This will panic if index is out of range.

Then you can iterate the fields:

  1. for fieldIx:=0;fieldIx&lt;item.NumField();fieldIx++ {
  2. field:=item.Field(fieldIx)
  3. }

huangapple
  • 本文由 发表于 2022年7月28日 05:07:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/73144621.html
匿名

发表评论

匿名网友

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

确定