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

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

Iterating slice struct within struct using reflection

问题

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

使用案例:

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

示例代码:

type Foo struct {
	Hello string
	World []Bar
}

type Bar struct {
	Fish string
}

type Result struct {
	Field string

	Correct_A  bool
	Distance_A int

	Correct_B  bool
	Distance_B int

	Result []Result
}

func compare_structs() {
	var full, a, b Foo

	// 填充所有变量...

	result := []Result{}

	rfx_f := reflect.ValueOf(full)
	rfx_a := reflect.ValueOf(a)
	rfx_b := reflect.ValueOf(b)

	type_result := rfx_f.Type()

	for i := 0; i < rfx_f.NumField(); i++ {
		tmp_res := Result{
			Field: type_result.Field(i).Name,
		}

		if reflect.TypeOf(full).Field(i).Type.Kind() != reflect.Slice {
			value := rfx_f.Field(i).Interface()
			value_a := rfx_a.FieldByName(tmp_res.Field).Interface()
			value_b := rfx_b.FieldByName(tmp_res.Field).Interface()

			// 比较该字段的值的函数
			tmp_res.compare(value, value_a, value_b)
			tmp_res.lev(value, value_a, value_b)

			result = append(result, tmp_res)
		} else if tmp_res.Field == "World" {
			/*
				我需要获取Foo结构体中Bar切片的第一个索引。
				即使变量是一个切片,我知道在这个案例中它的长度始终为1。
				获取后,我需要像前一个if语句中所发生的那样循环遍历这些字段。
			*/
		}

	}
}
英文:

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:

type Foo struct {
	Hello string
	World []Bar
}

type Bar struct {
	Fish string
}

type Result struct {
	Field string

	Correct_A  bool
	Distance_A int

	Correct_B  bool
	Distance_B int

	Result []Result
}

func compare_structs() {
	var full, a, b Foo

	// filling in all variables...

	result := []Result{}

	rfx_f := reflect.ValueOf(full)
	rfx_a := reflect.ValueOf(a)
	rfx_b := reflect.ValueOf(b)

	type_result := rfx_f.Type()

	for i := 0; i &lt; rfx_f.NumField(); i++ {
		tmp_res := Result{
			Field: type_result.Field(i).Name,
		}

		if reflect.TypeOf(full).Field(i).Type.Kind() != reflect.Slice {
			value := rfx_f.Field(i).Interface()
			value_a := rfx_a.FieldByName(tmp_res.Field).Interface()
			value_b := rfx_b.FieldByName(tmp_res.Field).Interface()

			// functions to compare the values of this field
			tmp_res.compare(value, value_a, value_b)
			tmp_res.lev(value, value_a, value_b)

			result = append(result, tmp_res)
		} else if tmp_res.Field == &quot;World&quot; {
			/*
				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.
			*/
		}

	}
}

答案1

得分: 1

你首先需要获取字段:

wordField := rfx_f.Field(i)

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

item := wordField.Index(0)

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

然后你可以迭代字段:

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

You first need to get the field:

wordField:=rfx_f.Field(i)

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

item:=wordField.Index(0)

This will panic if index is out of range.

Then you can iterate the fields:

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

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:

确定