I have the following package:
// Contains state read in from the command line
type State struct {
Domain string // Domain to check for
DomainList string // File location for a list of domains
OutputNormal string // File to output in normal format
OutputDomains string // File to output domains only to
Verbose bool // Verbose prints, incl. Debug information
Threads int // Number of threads to use
NoColour bool // Strip colour from output
Silent bool // Output domains only
Usage bool // Print usage information
}
func InitState() (state State) {
return State { "", "", "", "", false, 20, false, false, false }
}
func ValidateState(s *State) (result bool, error string ) {
if s.Domain == "" && s.DomainList == "" {
return false, "You must specify either a domain or list of domains to test"
}
return true, ""
}
Within ValidateState() I would like to return true if every item in State is the same as what is defined in InitState(). I can see a few ways to do this, but nothing that seems concise. I would greatly value some direction!
Struct values are comparable if all their fields are comparable (see Spec: Comparison operators). And since in your case this holds, we can take advantage of this.
In your case the simplest and most efficient way to achieve this is to save a struct value holding the initial value, and whenever you want to tell if a struct value (if any of its fields) has changed, simply compare it to the saved, initial value. This is all it takes:
var defaultState = InitState()
func isUnchanged(s State) bool {
return s == defaultState
}
Testing it:
s := InitState()
fmt.Println(isUnchanged(s))
s.Threads = 1
fmt.Println(isUnchanged(s))
Output (try it on the Go Playground):
true
false
Note that this solution will still work without any modification if you change the State type by adding / removing / renaming / rearranging fields as long as they all will still be comparable. As a counter example, if you add a field of slice type, it won't work anymore as slices are not comparable. It will result in a compile-time error. To handle such cases, reflect.DeepEqual() might be used instead of the simple == comparison operator.
Also note that you should create default values of State like this:
func NewState() State {
return State{Threads: 20}
}
You don't have to list fields whose values are the zero values of their types.
Related
If I'm passing an int value in a struct (in my particular case, rpc arguments), the language does not allow the attribute to be nil. The empty value for an int is 0.
But Go uses 0-indexed arrays. I need a way to differentiate between an empty value and an index of 0. Is there an idiomatic go solution for this problem?
// this is psuedo-code I had written before hitting this problem
if (args.maybeIndex != nil) {
doSomething(sliceOfNodes[args.maybeIndex])
}
If you encode your ints by value, then there's not much you can do about it - the default value is 0.
A common way to ensure nullability in encodings in Go is to use pointer types. Using a *int instead of an int lets you distinguish between "none" and 0.
E.g. with a JSON example, consider the struct:
type Options struct {
Id *string `json:"id,omitempty"`
Verbose *bool `json:"verbose,omitempty"`
Level *int `json:"level,omitempty"`
Power *int `json:"power,omitempty"`
}
And this data:
{
"id": "foobar",
"verbose": false,
"level": 10
}
Note that "power" is not specified. You could write a deserializer:
func parseOptions(jsn []byte) Options {
var opts Options
if err := json.Unmarshal(jsonText, &opts); err != nil {
log.Fatal(err)
}
if opts.Power == nil {
var v int = 10
opts.Power = &v
}
return opts
}
That sets a default value to "power", if it's not specified. This lets you distinguish between "power was not present" and "power was present and its value was 0".
If your encoding / RPC mechanism does not permit pointers, you could work around this by having another boolean field called "index present" or something like this.
Finally, consider designing your program to make it resilient to the difference between "not set" and "set to default value". IOW, just accept that default values and unspecified data are one and the same. In the long term, this will result in a cleaner design and code, and will be less error prone.
I'm trying to create a function that will produce an if condition from a predefined array.
for example:
package errors
type errorCase struct {
// This is the field I need to get in another struct
Field string
// The comparison operator
TestOperator string
// The value that the expected one should not with equal...
WrongValue interface{}
}
var ErrorCases = []*errorCase{ {
"MinValue",
"<",
0,
}, {
"MaxValue",
"==",
0,
}}
Actually I made a new function with a for loop that iterate through all of these "error cases"
func isDirty(questionInterface models.QuestionInterface) bool {
for _, errorCase := range errors.ErrorCases {
s := reflect.ValueOf(&questionInterface).Elem()
value := s.Elem().FieldByName(errorCase.Field)
// At this point I need to create my if condition
// to compare the value of the value var and the wrong one
// With the given comparison operator
}
// Should return the comparison test value
return true
}
Is that possible to create an if condition like that?
With the reflect package?
I think this is possible but I don't find where I should start.
This is possible. I built a generic comparison library like this once before.
A comparison, in simple terms, contains 3 parts:
A value of some sort, on the left of the comparison.
An operator (=, <, >, ...).
A value of some sort, on the right of the comparison.
Those 3 parts, contain only two different types - value and operator. I attempted to abstract those two types into their base forms.
value could be anything, so we use the empty interface - interface{}.
operator is part of a finite set, each with their own rules.
type Operator int
const (
Equals Operator = 1
)
Evaluating a comparison with an = sign has only one rule to be valid - both values should be of the same type. You can't compare 1 and hello. After that, you just have to make sure the values are the same.
We can implement a new meta-type that wraps the requirement for evaluating an operator.
// Function signature for a "rule" of an operator.
type validFn func(left, right interface{}) bool
// Function signature for evaluating an operator comparison.
type evalFn func(left, right interface{}) bool
type operatorMeta struct {
valid []validFn
eval evalFn
}
Now that we've defined our types, we need to implement the rules and comparison functions for Equals.
func sameTypes(left, right interface{}) bool {
return reflect.TypeOf(left).Kind() == reflect.TypeOf(right).Kind()
}
func equals(left, right interface{}) bool {
return reflect.DeepEqual(left, right)
}
Awesome! So we can now validate that our two values are of the same type, and we can compare them against each other if they are. The last piece of the puzzle, is mapping the operator to its appropriate rules and evaluation and having a function to execute all of this logic.
var args = map[Operator]operatorMeta{
Equals: {
valid: []validFn{sameTypes},
eval: equals,
},
}
func compare(o Operator, left, right interface{}) (bool, error) {
opArgs, ok := args[o]
if !ok {
// You haven't implemented logic for this operator.
}
for _, validFn := range opArgs.valid {
if !validFn(left, right) {
// One of the rules were not satisfied.
}
}
return opArgs.eval(left, right), nil
}
Let's summarize what we have so far:
Abstracted a basic comparison into a value and operator.
Created a way to validate whether a pair of values are valid for an operator.
Created a way to evaluate an operator, given two values.
(Go Playground)
I hope that I gave some insight into how you can approach this. It's a simple idea, but can take some boilerplate to get working properly.
Good luck!
Looking at this struct:
type Config struct {
path string
id string
key string
addr string
size uint64
}
Now I have a DefaultConfig intialized with some values and one loaded from a file, let's say FileConfig.
I want both structs to me merged, so that I get a Config with the content of both structs. FileConfig should override anything set in DefaultConfig, while FileConfig may not have all fields set.
(Why this? Because a potential user may not know the default value, so removing that entry would be equivalent to setting the default - I think)
I thought I'd need reflection for this:
func merge(default *Config, file *Config) (*Config) {
b := reflect.ValueOf(default).Elem()
o := reflect.ValueOf(file).Elem()
for i := 0; i < b.NumField(); i++ {
defaultField := b.Field(i)
fileField := o.Field(i)
if defaultField.Interface() != reflect.Zero(fileField.Type()).Interface() {
defaultField.Set(reflect.ValueOf(fileField.Interface()))
}
}
return default
}
Here I am not sure:
If reflection is needed at all
There may be easier ways to do this
Another issue I see here is that checking for zero values may be tricky: what if the overriding struct intends to override with a zero value? Luckily, I don't think it applies to my case - but this becomes a function, it may become a problem later
Foreword: The encoding/json package uses reflection (package reflect) to read/write values, including structs. Other libraries also using reflection (such as implementations of TOML and YAML) may operate in a similar (or even in the same way), and thus the principle presented here may apply to those libraries as well. You need to test it with the library you use.
For simplicity, the solution presented here uses the standard lib's encoding/json.
An elegant and "zero-effort" solution is to use the encoding/json package and unmarshal into a value of the "prepared", default configuration.
This handles everything you need:
missing values in config file: default applies
a value given in file overrides default config (whatever it was)
explicit overrides to zero values in the file takes precedence (overwrites non-zero default config)
To demonstrate, we'll use this config struct:
type Config struct {
S1 string
S2 string
S3 string
S4 string
S5 string
}
And the default configuration:
var defConfig = &Config{
S1: "", // Zero value
S2: "", // Zero value
S3: "abc",
S4: "def",
S5: "ghi",
}
And let's say the file contains the following configuration:
const fileContent = `{"S2":"file-s2","S3":"","S5":"file-s5"}`
The file config overrides S2, S3 and the S5 fields.
Code to load the configuration:
conf := new(Config) // New config
*conf = *defConfig // Initialize with defaults
err := json.NewDecoder(strings.NewReader(fileContent)).Decode(&conf)
if err != nil {
panic(err)
}
fmt.Printf("%+v", conf)
And the output (try it on the Go Playground):
&{S1: S2:file-s2 S3: S4:def S5:file-s5}
Analyzing the results:
S1 was zero in default, was missing from file, result is zero
S2 was zero in default, was given in file, result is the file value
S3 was given in config, was overriden to be zero in file, result is zero
S4 was given in config, was missing in file, result is the default value
S5 was given in config, was given in file, result is the file value
Reflection is going to make your code slow.
For this struct I would implement a straight Merge() method as:
type Config struct {
path string
id string
key string
addr string
size uint64
}
func (c *Config) Merge(c2 Config) {
if c.path == "" {
c.path = c2.path
}
if c.id == "" {
c.id = c2.id
}
if c.path == "" {
c.path = c2.path
}
if c.addr == "" {
c.addr = c2.addr
}
if c.size == 0 {
c.size = c2.size
}
}
It's almost same amount of code, fast and easy to understand.
You can cover this method with uni tests that uses reflection to make sure new fields did not get left behind.
That's the point of Go - you write more to get fast & easy to read code.
Also you may want to look into go generate that will generate the method for you from struct definition. Maybe there event something already implemented and available on GitHub? Here is an example of code that do something similar: https://github.com/matryer/moq
Also there are some packages on GitHub that I believe are doing what you want in runtime, for example: https://github.com/imdario/mergo
Another issue I see here is that checking for zero values may be
tricky: what if the overriding struct intends to override with a zero
value?
In case you cannot utilize encoding/json as pointed out by icza or other format encoders that behave similarly you could use two separate types.
type Config struct {
Path string
Id string
Key string
Addr string
Size uint64
}
type ConfigParams struct {
Path *string
Id *string
Key *string
Addr *string
Size *uint64
}
Now with a function like this:
func merge(conf *Config, params *ConfigParams)
You could check for non-nil fields in params and dereference the pointer to set the value in the corresponding fields in conf. This allows you to unset fields in conf with non-nil zero value fields in params.
This solution won't work for your specific question, but it might help someone who has a similar-but-different problem:
Instead of creating two separate structs to merge, you can have one "default" struct, and create a modifier function for it. So in your case:
type Config struct {
path string
id string
key string
addr string
size uint64
}
var defcfg = Config {
path: "/foo",
id: "default",
key: "key",
addr: "1.2.3.4",
size: 234,
}
And your modifier function:
func myCfg(c *Config) {
c.key = "different key"
}
This works in tests where I want to test many small, different variations of a largely unmodified struct:
func TestSomething(t *testing.T) {
modifiers := []func (*Config){
.... // modifier functions here
}
for _, f := range modifiers {
tc := defcfg // copy
f(&tc)
// now you can use tc.
}
}
Not useful when you read your modified config from a file into a struct, though. On the plus side: this also works with zero values.
I have a service, written in golang, that can be initialized with some options. Options are passed as a struct to a constructor function. The constructor function uses default values for option fields that weren't included. Here's an example:
type Service struct {
options Options
}
type Options struct {
BoolOption bool
StringOption string
}
const (
DefaultBoolOption = true
DefaultStringOption = "bar"
)
func New(opts Options) *Service {
if !opts.BoolOption {
opts.BoolOption = DefaultBoolOption
}
if len(opts.StringOption) < 1 {
opts.StringOption = DefaultStringOption
}
return &Service{options: opts,}
}
...
// elsewhere in my code
o := Options{BoolOption: false,}
// sets s.options.BoolOption to true!!!
s := New(o)
My problem is that for bool or int option types, I can't tell whether or not a field value was set in the Options struct. For example, was BoolOption set to false or just not initialized?
One possible solution would be to use strings for all of my Options fields. For instance, BoolOption would be "false" rather than false. I could then check the length of the string to check if it was initialized.
Are there better solutions?
For detecting uninitialized struct fields, as a rule certain types have zero values, they are otherwise nil (maps and channels need to be maked):
var i int // i = 0
var f float64 // f = 0
var b bool // b = false
var s string // s = ""
var m chan int// c = nil
There is a tour slide which is useful.
I think you're problem involves creating a default boolean value of true
For your sake, however, if you are passing an Option struct into that function, and the user did not specify the options, then yes they will be false and "" by default.
One solution is to create a(nother) constructor: func NewOptions(b bool, s string) Options
This constructor would make the bool default true.
You could also try an enum to simulate a boolean; the zero value will be 0. So instead of type bool for the Options struct value BoolOption, you could use int:
const (
TRUE
FALSE
)
You could also have a UNINITIALIZED as zero, but I think you just want to switch the default value, rather than detecting that it is uninitialized.
So when checking a value of Options, you could write:
if opt.BoolOption == FALSE {
// Do something with the option
} else {
// The default option
}
A bit simpler would be to make the BoolOption into notBoolOption, and have the default be false.
Or, as Olivia Ruth points out, if you have the field as a pointer to a boolean, it will be remain nil until "initialized".
The default value for a bool is false. If you notice that you are overwriting the options value to true every time you run the code.
The default values of a strings variable is "". So if check the string with len(opts.StringOption) == 0 or opts.StringOption == "" that would work as well.
https://play.golang.org/p/jifZZvoBVZ
I have problem with resolve whether object which was pass as interface to function hasn't initializated fields, like object which was defined as just someObject{} is a empty, because all fields, has value 0, or nil
Problem becomes more complicated if I pass diffrent objects, because each object have diffrent type field value so on this moment I don't find universal way to this.
Example
func main(){
oo := objectOne{}
ot := objectTwo{}
oth := objectThree{"blah" , "balbal" , "blaal"}
resolveIsNotIntialized(oo)
resolveIsNotIntialized(ot)
resolveIsNotIntialized(oth)
}
func resolveIsNotIntialized(v interface{}) bool{
// and below, how resolve that oo and ot is empty
if (v.SomeMethodWhichCanResolveThatAllFiledIsNotIntialized){
return true
}
return false
}
I want to avoid usage switch statement like below, and additional function for each object, ofcorse if is possible.
func unsmartMethod(v interface{}) bool{
switch v.(type){
case objectOne:
if v == (objectOne{}) {
return true
}
// and next object, and next....
}
return false
}
As Franck notes, this is likely a bad idea. Every value is always initialized in Go. Your actual question is whether the type equals its Zero value. Generally the Zero value should be designed such that it is valid. The better approach would generally be to create an interface along the lines of:
type ZeroChecker interface {
IsZero() bool
}
And then attach that to whatever types you want to check. (Or possibly better: create an IsValid() test instead rather than doing your logic backwards.)
That said, it is possible to check this with reflection, by comparing it to its Zero.
func resolveIsNotIntialized(v interface{}) bool {
t := reflect.TypeOf(v)
z := reflect.Zero(t).Interface()
return reflect.DeepEqual(v, z)
}
(You might be able to get away with return v == z here; I haven't thought through all the possible cases.)
I don’t think there is a good reason (in idiomatic Go) to do what you are trying to do. You need to design your structs so that default values (nil, empty string, 0, false, etc.) are valid and represent the initial state of your object. Look at the source of the standard library, there are lots of examples of that.
What you are suggesting is easily doable via Reflection but it will be slow and clunky.
You could narrow the type which your function takes as an argement a little, not take an interface{} but accept one that allows you to check for non-zero values, say type intercae{nonZero() bool} as in the example code below. This will not tell you explicitly that it hasn't been set to the zero value, but that it is not zero.
type nonZeroed interface {
nonZero() bool
}
type zero struct {
hasVals bool
}
func (z zero) nonZero() bool {
return z.hasVals
}
type nonZero struct {
val int
}
func (nz nonZero) nonZero() bool {
return nz.val != 0
}
type alsoZero float64
func (az alsoZero) nonZero() bool {
return az != 0.0
}
func main() {
z := zero{}
nz := nonZero{
val: 1,
}
var az alsoZero
fmt.Println("z has values:", initialized(z))
fmt.Println("nz has values:", initialized(nz))
fmt.Println("az has values:", initialized(az))
}
func initialized(a nonZeroed) bool {
return a.nonZero()
}
Obviously as the type get more complex additional verification would need to be made that it was "nonZero". This type of pattern could be used to check any sort condition.