【问题标题】:Iterate through a struct with an embedded struct遍历具有嵌入结构的结构
【发布时间】:2020-03-05 11:48:26
【问题描述】:

我有几个正在接收数据的结构。所有结构都应包含一些相同的数据,这些数据已嵌入HeaderData 结构中。数据不是同时填充的,我需要一个函数来检查是否所有的字段都收到了一个值(不是空字符串)。

我试图用反射解决这个问题。问题是反射会将HeaderData 视为一个字段。这意味着它将始终是一个非空字符串,尽管它可能包含空字段。所以我相信我需要一种方法来单独检查该结构。

我尝试使用 anyStruct.HeaderData 访问它,但这不起作用,因为“{} 是没有方法的接口”。

还有其他方法可以访问HeaderData 以使其有效吗?

或者我能否以某种方式在dataReady 中指定输入必须包含HeaderData 字段?

package main

import (
    "fmt"
    "reflect"
)

type HeaderData struct {
    Param1  string
    Param2  string
}

type Data1 struct {
    HeaderData 
    Param3  string
    Param4  string
}

type Data2 struct {
    HeaderData 
    Param3  string
    Param5  string
}

func dataReady(anyStruct interface{}) bool {
    v := reflect.ValueOf(anyStruct)
    for i := 0; i < v.NumField(); i++ {
        // fmt.Println(v.Field(i).Interface())
        if v.Field(i).Interface() == "" {
            return false
        }
    }


    // v1 := reflect.ValueOf(anyStruct.HeaderData)
    // Not working:
    // anyStruct.HeaderData undefined (type interface {} is interface with no methods)

    return true
}

func main() {
    d1 := Data1{HeaderData: HeaderData{Param1: "ABC", Param2: "DEF"}, Param3: "GHI", Param4: "JKL"}
    d2 := Data2{HeaderData: HeaderData{Param1: "ABC", Param2: "DEF"}}
    d3 := Data2{HeaderData: HeaderData{Param1: "ABC"}, Param3: "GHI", Param5: "JKL"}
    d4 := Data2{Param3: "GHI", Param5: "JKL"}
    fmt.Println("d1Ready: ", dataReady(d1))     //Returns true, which is correct
    fmt.Println("d2Ready: ", dataReady(d2))     //Returns false, which is correct
    fmt.Println("d3Ready: ", dataReady(d3))     //Returns true but should return false
    fmt.Println("d4Ready: ", dataReady(d4))     //Returns true but should return false
}

Playground

【问题讨论】:

  • 您为什么需要对此进行反思?有一个方法/函数来检查HeaderData 的字段和那些DataN 结构的方法/函数;后者的方法/函数将调用方法/函数,该方法/函数将检查其中的 HeaderData field 的字段(它嵌入的事实并不排除通过其类型的名称访问它)。
  • 您可能认为这是“代码过多”,但作为交换,它更易于理解(而且速度更快)。
  • @kostix 这是一个选项,也许我应该这样做。但是正如您提到的那样,它将需要更多代码,每个结构我都需要一个函数。此外,如果结构发生变化,我将不得不更新函数。所以我认为如果我有一种更通用的检查方式会很好。

标签: go struct reflection embedding go-reflect


【解决方案1】:

也许尝试一个小界面来做同样的事情,我认为这会更具可读性。

https://play.golang.org/p/H4lh91RMd6C

package main

import (
     "fmt"
)

 type(

     FieldCheck interface {
         Check() (b bool)
     }

     HeaderData struct {
         Param1  string
         Param2  string
     }

    Data1 struct {
         HeaderData
         Param3  string
         Param4  string
     }

     Data2 struct {
         HeaderData
         Param3  string
         Param5  string
     }
  )

func(h *HeaderData) Check() (b bool) {
     if h.Param1 == "" || h.Param2 == "" {
         return false
     }
     return true
}

func(d *Data1) Check() (b bool) {
     if (d.Param3 == "" || d.Param4 == "" || ! d.HeaderData.Check()) {
         return false
     }
     return true
}

func(d *Data2) Check() (b bool) {
     if (d.Param3 == "" || d.Param5 == "" || ! d.HeaderData.Check()) {
         return false
     }
     return true
 }


func main() {

    d := []FieldCheck{
         &Data1{HeaderData: HeaderData{Param1: "ABC", Param2: "DEF"}, Param3: 
"GHI", Param4: "JKL"},
        &Data2{HeaderData: HeaderData{Param1: "ABC", Param2: "DEF"}},
        &Data2{HeaderData: HeaderData{Param1: "ABC"}, Param3: "GHI", Param5: 
"JKL"},
        &Data2{Param3: "GHI", Param5: "JKL"},
    }

    for _, num := range d {
        fmt.Println(num.Check())
    }
}

【讨论】:

  • 感谢您的建议!是的,这似乎是要走的路。缺点是如果将字段添加到结构中,还必须使用新字段更新 Check 方法。但希望结构会相当稳定:-)
  • 为简单起见,我这样做了,您可以循环结构每个级别的字段,因此不必这样做。你也可以有一个类型断言,让它更有活力。
  • 确实如此。谢谢:-)
猜你喜欢
  • 2021-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多