简体   繁体   中英

Iterate through a struct with an embedded struct

I have several structs that are receiving data. All structs shall include some of the same data, which have been embedded with the HeaderData struct. The data is not filled at the same time, and I need a function to check if all the fields have received a value (is not an empty string).

I tried to solve this with reflect. The problem is that reflect will consider the HeaderData to be one field. This means that it will always be a non-empty string, although it may include empty fields. So I believe that I need a way to check that struct separately.

I tried to access it with anyStruct.HeaderData , but that is not working since “{} is interface with no methods”.

Is there any other way to access the HeaderData so that this works?

Or can I in some way specify in the dataReady that the input must have the field 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

Perhaps try a little interface to do the same thing and i think that this would be a lot more readable.

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())
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM