Skip to content

Instantly share code, notes, and snippets.

@man0xff
Last active July 5, 2022 11:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save man0xff/32e3bfda16ffeabec4b802948be5ce52 to your computer and use it in GitHub Desktop.
Save man0xff/32e3bfda16ffeabec4b802948be5ce52 to your computer and use it in GitHub Desktop.
package util
import (
"fmt"
"reflect"
"strings"
)
// Use this function to ensure some struct properly inited. Tag `zero_ok`
// marks that this field can have zero value.
func EnsureStructInit(x interface{}) error {
val := reflect.Indirect(reflect.ValueOf(x))
if kind := val.Type().Kind(); kind != reflect.Struct {
return fmt.Errorf("struct or pointer to struct expected "+
"(type:'%v')", val.Type())
}
for i := 0; i < val.NumField(); i++ {
field := val.Type().Field(i)
if strings.Contains(string(field.Tag), "zero_ok") {
continue
}
if val.Field(i).IsZero() {
return fmt.Errorf("nil value (field:'%s')", field.Name)
}
}
return nil
}
package main
import (
"mymodule/util"
)
type Dep interface {
Do()
}
type Client struct {
dep Dep
}
// EnsureStructInit useful if there are lot of fields and
// it is difficult to check for nil all the pointers or interfaces
func NewClient(dep Dep) (*Client, error) {
c := &Client{
dep: dep,
}
// c.dep.Do() <- here we might panic
if err := util.EnsureStructInit(c); err != nil {
return nil, err
}
c.dep.Do() // here we are sure all fields inited
return c, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment