aquiseb
aquiseb

Reputation: 1009

How to check if all fields of a *struct are nil?

I'm not quite sure how to address this question, please feel free to edit.

With the first code block below, I am able to check if a all fields of a struct are nil.

In reality however, the values injected in the struct, are received as args.Review (see second code block below).

In the second code block, how can I check if all fields from args.Review are nil?

Try it on Golang Playground

package main

import (
    "fmt"
    "reflect"
)

type review struct {
    Stars      *int32  `json:"stars" bson:"stars,omitempty" `
    Commentary *string `json:"commentary" bson:"commentary,omitempty"`
}

func main() {

    newReview := &review{
        Stars: nil,
        // Stars:   func(i int32) *int32 { return &i }(5),

        Commentary: nil,
        // Commentary: func(i string) *string { return &i }("Great"),
    }

    if reflect.DeepEqual(review{}, *newReview) {
        fmt.Println("Nothing")
    } else {
        fmt.Println("Hello")
    }

}

Try the second code on Golang Playground This code below gets two errors:

prog.go:32:14: type args is not an expression

prog.go:44:27: args.Review is not a type

package main

import (
    "fmt"
    "reflect"
)

type review struct {
    Stars      *int32  `json:"stars" bson:"stars,omitempty" `
    Commentary *string `json:"commentary" bson:"commentary,omitempty"`
}

type reviewInput struct {
    Stars      *int32
    Commentary *string
}

type args struct {
    PostSlug string
    Review   *reviewInput
}

func main() {
    f := &args {
        PostSlug: "second-post",
        Review: &reviewInput{
            Stars:  func(i int32) *int32 { return &i }(5),
            Commentary: func(i string) *string { return &i }("Great"),
        },

    }
    createReview(args)
}

func createReview(args *struct {
    PostSlug string
    Review   *reviewInput
}) {
    g := &review{
        Stars: args.Review.Stars,
        Commentary: args.Review.Commentary,
    }

    if reflect.DeepEqual(args.Review{}, nil) {
        fmt.Println("Nothing")
    } else {
        fmt.Println("Something")
    }
}

Upvotes: 1

Views: 11039

Answers (1)

mkopriva
mkopriva

Reputation: 38303

If you're dealing with a small number of fields you should use simple if statements to determine whether they are nil or not.

if args.Stars == nil && args.Commentary == nil {
    // ...
}

If you're dealing with more fields than you would like to manually spell out in if statements you could use a simple helper function that takes a variadic number of interface{} arguments. Just keep in mind that there is this: Check for nil and nil interface in Go

func AllNil(vv ...interface{}) bool {
    for _, v := range vv {
        if v == nil {
            continue
        }

        if rv := reflect.ValueOf(v); !rv.IsNil() {
            return false
        }
    }
    return true
}

if AllNil(args.Stars, args.Commentary, args.Foo, args.Bar, args.Baz) {
    // ...
}

Or you can use the reflect package to do your bidding.

func NilFields(x interface{}) bool {
    rv := reflect.ValueOf(args)
    rv = rv.Elem()

    for i := 0; i < rv.NumField(); i++ {
        if f := rv.Field(i); f.IsValid() && !f.IsNil() {
            return false
        }
    }
    return true
}

if NilFields(args) {
   // ...
}

Upvotes: 7

Related Questions