2

Assume I have the following struct:

type myType struct {
    Qid, Interval, RoundNumber string
}

and I have to make sure that a variable of type myType does not have an empty string value for any of the properties.

Is there a more idiomatic way than doing the following if:

if aMyType.Qid == "" || aMyType.Interval == "" || aMyType.RoundNumber == "" {
  // handle error situation
}

Obviously the if works but I was wondering whether Go has a better way?

Ralf
  • 2,512
  • 4
  • 24
  • 26

3 Answers3

8

You might define a function on myType that would make it easier to determine validity:

func (m myType) Valid() bool {
    return m.Qid != "" && m.Interval != "" && m.RoundNumber != ""
}

And then:

if aMyType.Valid() {
    // ...
}
Jimmy Sawczuk
  • 13,488
  • 7
  • 46
  • 60
  • I like this a lot. Sometimes forgetting about types allowing to associated methods... too much into the class inheritance world I guess. Thanks! Good Idea! – Ralf Feb 28 '14 at 18:28
1

I won't claim it's idiomatic, but if you want to play around with reflection... You can dynamically inspect the exported (capital first letter) fields of a struct. This example inspects all of the exported strings in the struct for non-empty. This doesn't handle nested structs.

http://play.golang.org/p/IjMW8OJKlc

type myType struct {
    Number  int
    A, b, C string
}

This works by only checking for empty on exported string types.

func (m *myType) IsValid() bool {

    v := reflect.ValueOf(*m)

    for i := 0; i < v.NumField(); i++ {
        sv := v.Field(i)
        if sv.Kind() == reflect.String && sv.CanInterface() && sv.Interface() == "" {
            return false
        }
    }
    return true
}

func main() {
    // false
    fmt.Println((&myType{}).IsValid())
    // true
    fmt.Println((&myType{A: "abc", C: "123"}).IsValid())
}
bolts
  • 31
  • 3
0

For simple cases as you mentioned, I think the method you provided is more natural and more idiomatic in Go:

if mt.Qid == "" || mt.Interval == "" || mt.RoundNumber == "" {
    // handle error situation
}

But if your struct is non-trivial and the validation rule is complicated, then it may be more idiomatic to leverage a dedicated library such as validating. See here for a slightly more complex use-case, and here for a very complicated use-case.

As a contrast, by using validating, the validation rule you mentioned can be implemented as follows:

import v "github.com/RussellLuo/validating"

errs := v.Validate(v.Schema{
    v.F("qid", &mt.Qid):                  v.Nonzero(),
    v.F("interval", &mt.Interval):        v.Nonzero(),
    v.F("round_number", &mt.RoundNumber): v.Nonzero(),
})
RussellLuo
  • 155
  • 2
  • 9