Initialize structs with default values

Overview

defaults

Build Status codecov GitHub release License

Initialize structs with default values

  • Supports almost all kind of types
    • Scalar types
      • int/8/16/32/64, uint/8/16/32/64, float32/64
      • uintptr, bool, string
    • Complex types
      • map, slice, struct
    • Aliased types
      • time.Duration
      • e.g., type Enum string
    • Pointer types
      • e.g., *SampleStruct, *int
  • Recursively initializes fields in a struct
  • Dynamically sets default values by defaults.Setter interface
  • Preserves non-initial values from being reset with a default value

Usage

type Gender string

type Sample struct {
	Name   string `default:"John Smith"`
	Age    int    `default:"27"`
	Gender Gender `default:"m"`

	Slice       []string       `default:"[]"`
	SliceByJSON []int          `default:"[1, 2, 3]"` // Supports JSON
	Map         map[string]int `default:"{}"`
	MapByJSON   map[string]int `default:"{\"foo\": 123}"`

	Struct    OtherStruct  `default:"{}"`
	StructPtr *OtherStruct `default:"{\"Foo\": 123}"`

	NoTag  OtherStruct               // Recurses into a nested struct by default
	OptOut OtherStruct `default:"-"` // Opt-out
}

type OtherStruct struct {
	Hello  string `default:"world"` // Tags in a nested struct also work
	Foo    int    `default:"-"`
	Random int    `default:"-"`
}

// SetDefaults implements defaults.Setter interface
func (s *OtherStruct) SetDefaults() {
	if defaults.CanUpdate(s.Random) { // Check if it's a zero value (recommended)
		s.Random = rand.Int() // Set a dynamic value
	}
}
obj := &Sample{}
if err := defaults.Set(obj); err != nil {
	panic(err)
}
Comments
  • Default value to the entry that key already exists in a map

    Default value to the entry that key already exists in a map

    Hi, thank you for making and maintaining such an amazing package. It helps me a lot!

    I'm facing an issue that is not able to set default values within a map[string]struct{}. I'd like to set the default value to the entry that key already exists in a map. But it doesn't work well:

    package main
    
    import (
    	"fmt"
    
    	"github.com/creasty/defaults"
    )
    
    type T struct {
    	Field string `default:"value-1"`
    }
    
    type Foo struct {
    	Map map[string]T
    	T   T
    }
    
    func main() {
    	f := &Foo{
    		Map: map[string]T{
    			// I want to set the default value here.
    			"key-1": T{},
    		},
    	}
    	if err := defaults.Set(f); err != nil {
    		panic(err)
    	}
    	fmt.Printf("field in map: %q\n", f.Map["key-1"].Field)
    	fmt.Printf("field in struct: %q\n", f.T.Field)
    
    	// Output:
    	//
    	// field in map: ""
    	// field in struct: "value-1"
    }
    

    Currently, I workaround like:

    	for k, v := range f.Map {
    		_ = defaults.Set(&v)
    		f.Map[k] = v
    	}
    

    Is there another way to set a default value for a value that already has a key in the map?

    Thanks!

    opened by nakabonne 5
  • Set the default value for a pointers (non-struct) when it is nil only.

    Set the default value for a pointers (non-struct) when it is nil only.

    Usually, in our projects, we read a JSON configuration file into a struct and invoke the defaults.Set() function to set the default values of non initialized fields. When one of the configuration parameters is a boolean and we set its default value to true, it cannot use the JSON configuration file to set it as false, because Set() assumes it using the default value and modifies it to true. In order to solve this, we decided to use pointers to boolean that can be nil when the field does not appear in the configuration file. In such a scenario, defaults.Set() works fine as expected assigning true to the boolean field, however, when in the JSON configuration file the boolean parameter is set to false, then defaults.Set() ignores that the pointer already has a value different from nil, gets the pointer value, checks that it is false, and modifies it to true what is not desired.

    As a proposal, this PR just skips the setFields() function when the pointer is not nil and not a struct. Using this approach, the nil value will be the trigger to set the default value which makes sense since the Zero() value for pointers is nil.

    opened by mmpereira2github 4
  • How to support slice of struct?

    How to support slice of struct?

    For example:

    type confModule struct {
    	Name   string   `yaml:"name" default:"abc"`
    	Params []string `yaml:"params" default:"[\"-c\", \"conf.yml\"]"`
    }
    
    type confStruct struct {
    	ID     string       `yaml:"id"`
    	Modules []confModule `yaml:"modules"`
    }
    

    defaults will skip the slice of struct (confStruct.Modules), how to support this case?

    opened by ludanfeng 4
  • Unable to keep zero value in case of setting the zero value on purpose

    Unable to keep zero value in case of setting the zero value on purpose

    Hi @creasty, thanks for the excellent package. I faced a typical case but am unsure how to use your package to address that.

    In the case of the field of type bool, the go default bool value is false - boolean zero value. If I want to set the default value to true with your defaults package, it works as expected in case no value was set to that field. If the value for that field is set to zero value on purpose (bool zero is false), the defaults.Set() always override that field value with the configured value regardless of the original value.

    package main
    
    import (
    	"fmt"
    	"github.com/creasty/defaults"
    )
    
    type Sample struct {
    	Hello  string `default:"world"` // Tags in a nested struct also work
    	Foo    int    `default:"-"`
    	Random int    `default:"-"`
    	Bool   bool   `default:"true"`
    }
    
    func main() {
    	obj := &Sample{Hello: "hello", Bool: false}
    	if err := defaults.Set(obj); err != nil {
    		panic(err)
    	}
    	fmt.Println(obj)
    }
    

    I tried with defaults.CanUpdate(obj.Bool) too, but it looks like it checks for the zero value of type and compares with the current set value, which is already a zero value, hence not have any meaning here since the set value is zero value.

    In case of check with defaults.CanUpdate(obj), all the values will not be set since obj.Hello is not zero value of string, and that cause obj.Bool will not be set to true in case it's not yet set.

    play: https://play.golang.org/p/5LoqUH5d1wj

    opened by khanhtc1202 2
  • Booleans and defaults seems not to be working

    Booleans and defaults seems not to be working

    Hi, I'm trying to use this library but I'm facing an issue setting defaults values for a boolean field

    In my example, I am setting a boolean default value to true for the Enabled field but when passing a false value it turns to true

    package main
    
    import (
    	"fmt"
    	"github.com/creasty/defaults"
    )
    
    type Sample struct {
    	Enabled bool `default:"true"`
    }
    
    func main() {
    	obj := &Sample{Enabled: false}
    	if err := defaults.Set(obj); err != nil {
    		panic(err)
    	}
    	fmt.Printf("%+v\n", obj)
    }
    

    Output: &{Enabled:true}

    am I missing something?

    Here is a playground where you can test it: https://play.golang.org/p/RIeiduC2c8C

    opened by datencia 2
  • Default values map[string][]string for struct

    Default values map[string][]string for struct

    Hi Team !

    i have tried with map[string][]string but not work. does have support it?

    type HttpVar struct {
            AttrHeader 		map[string]string `default:"[]string{\"foo\":\"test\"}"`
    	Wrapper 			interface{}
    }
    
    opened by songhanpoo 2
  • Allow to use integer literals

    Allow to use integer literals

    As says in strconv.ParseInt documentation:

    "If the base argument is 0, the true base is implied by the string's prefix: 2 for "0b", 8 for "0" or "0o", 16 for "0x", and 10 otherwise. Also, for argument base 0 only, underscore characters are permitted as defined by the Go syntax for integer literals. "

    This allow to use hexadecimal , octal or binary to define integer default values. With this PR is posible to use other notations accord its context without break current behaviour for integers.

    Examples:

    • define file permisions in octal notation 0644 instead of 420 in decimal
    • define RGB color with 0xFFA07A as LightSalmon
    • define flags in binary like 0b1010100

    Breaking changes

    This PR require at least go1.13

    Fixed

    Potential error in 32 bit systems because int and uint are assumed as 64 bit long

    opened by licaonfee 2
  • Default true on bool does not allow to set false

    Default true on bool does not allow to set false

    I explain myself since the title might looks a bit rubbish. Basically I have a yaml file (not official one)

    foo:
       bar: false # You can play of changing this to true / false
    

    I have my configuration in go:

    type Foo struct {
      Bar bool `default:"true" yaml:"bar"`
    }
    

    when I do run my defaults I have something like this:

    	if err := defaults.Set(myConfig); err != nil {
    		panic(err)
    	}
           fmt.Printf("Show me the value: %v", myConfig.Bar)
           // The result it always show: Show me the value: true
    

    I don't have any issue with any other default except the boolean type.

    Note: I didn't try to run the code currently here, but it represents pretty much what it looks like in my code. I have my code in a not so public repo.

    opened by Nordes 1
  • Wrong example in Readme?

    Wrong example in Readme?

    I see the following code.

    	StructPtr *OtherStruct `default:"{\"Foo\": 123}"`
    

    It may be wrong, because OtherStruct is not an integer.

    opened by ghost 1
  • no errors if default value doesn't parse

    no errors if default value doesn't parse

    If the value in the default tag is not parseable as the type of the field, there is no error returned. Is this intended? For example:

    type Widget struct {
      Colors []string `env:"[red,blue]"`
    }
    
    func main() {
      var c Colors
      err := defaults.Set(&c)
    
      fmt.Println("err: ", err) // nothing printed, no error
    
      fmt.Println(c.Colors) // nothing printed, tag value was not valid JSON, so parsing silently failed
    }
    
    opened by ansel1 1
  • nil slices, maps, and pointers are initialized to non-nil values

    nil slices, maps, and pointers are initialized to non-nil values

    If a struct has map, slice, or pointer fields which have an initial value of nil, Set() will set them to empty (zero) values, even if the field has no "default" tag. See this test case:

    type TT struct{}
    
    type SS struct {
    	Ptr *TT
    	Slice []string
    	Map map[string]interface{}
    }
    
    func TestEmptySlice(t *testing.T) {
    	s := SS{}
    	err := Set(&s)
    	if err != nil {
    		t.Fatalf("Set() returned error: %#v", err)
    	}
    
    	if s.Ptr != nil {
    		t.Error("Set() initialized nil pointer")
    	}
    
    	if s.Slice != nil {
    		t.Error("Set() initialized nil slice")
    	}
    
    	if s.Map != nil {
    		t.Error("Set() initialized nil map")
    	}
    }
    

    Seems like, if the field has no "default" tag, and there is nothing to recurse into (because the value is nil), it should be left unchanged.

    I think this was a side effect of the last change for recursing into nested values with no "default" tag.

    opened by ansel1 1
  • bug: []time.Duration not works

    bug: []time.Duration not works

    Example struct

    type MyStruct struct {
        BackoffPolicy []time.Duration `default:"...."`
    }
    

    Checked variants:

    • default:"{[\"10s\",\"1m\"]}"
    • default:"[\"10s\",\"1m\"]"
    • default:"[10s,1m]"
    • default:"\"10s\",\"1m\""
    • default:"10s,1m"

    all of them not works

    opened by ergoz 0
  • Add require field tag

    Add require field tag

    It would be fantastic if this library had the option to set a struct field as required. Then when defaults.Set is called on a struct with zero value fields that are marked as required the function returns an error.

    opened by NilsJPWerner 0
  • Customizable value filler

    Customizable value filler

    Why

    To enable stuff like add support time scalar type on users' end.

    What

    I found this library that does more or less what I envision: https://github.com/mcuadros/go-defaults/blob/master/filler.go

    opened by creasty 0
  • Default value for slice of struct doesn't work for golang v 1.12

    Default value for slice of struct doesn't work for golang v 1.12

    package controllers
    
    import (
    	"fmt"
    
    	"github.com/creasty/defaults"
    )
    
    func main() {
    
    	foo := &Parent{}
    	if err := defaults.Set(foo); err != nil {
    		fmt.Println(err)
    	}
    	fmt.Print(foo)
    }
    
    type Child struct {
    	Name string
    	Age  int `default:"33"`
    }
    
    type Parent struct {
    	children []Child
    }
    
    

    output: &{[]}

    opened by pavankumar-bit 2
Releases(v1.6.0)
Owner
Yuki Iwanaga
A full-stack engineer pursuing beauty in both design and engineering.
Yuki Iwanaga
Default godoc generator - make your first steps towards better code documentation

godoc-generate Overview godoc-generate is a simple command line tool that generates default godoc comments on all exported types, functions, consts an

Dimitar Petrov 19 Sep 14, 2022
RTS: request to struct. Generates Go structs from JSON server responses.

RTS: Request to Struct Generate Go structs definitions from JSON server responses. RTS defines type names using the specified lines in the route file

Paolo Galeone 236 Nov 26, 2022
Best-effort CPU-local sharded values for Go

percpu Percpu is a Go package to support best-effort CPU-local sharded values. This package is something of an experiment. See Go issue #18802 for dis

Caleb Spare 179 Nov 9, 2022
Type-safe atomic values for Go

Type-safe atomic values for Go One issue with Go's sync/atomic package is that there is no guarantee from the type system that operations on an intege

Alec Thomas 17 Apr 8, 2022
Package reservoir samples values uniformly at random from an unbounded sequence of inputs

Package reservoir samples values uniformly at random from an unbounded sequence of inputs

null 1 Oct 5, 2022
Library for setting values to structs' fields from env, flags, files or default tag

Configuration is a library for injecting values recursively into structs - a convenient way of setting up a configuration object. Available features:

Bogdan Daragan 82 Oct 25, 2022
Enforce default values on structs in Go

Defaults Enforce default values on struct fields. type User struct { Name string `default:"Goku"` Power float64 `default:"9000.01"` } var u

Christian Rocha 26 Aug 23, 2022
K8s-go-structs - All k8s API Go structs

k8s-api go types Why? Its nice to have it all in a single package. . |-- pkg |

 Aatman 3 Jul 17, 2022
[UNMANTEINED] Extract values from strings and fill your structs with nlp.

nlp nlp is a general purpose any-lang Natural Language Processor that parses the data inside a text and returns a filled model Supported types int in

Juan Alvarez 379 Nov 24, 2022
:steam_locomotive: Decodes url.Values into Go value(s) and Encodes Go value(s) into url.Values. Dual Array and Full map support.

Package form Package form Decodes url.Values into Go value(s) and Encodes Go value(s) into url.Values. It has the following features: Supports map of

Go Playgound 568 Dec 6, 2022
[爬虫框架 (golang)] An awesome Go concurrent Crawler(spider) framework. The crawler is flexible and modular. It can be expanded to an Individualized crawler easily or you can use the default crawl components only.

go_spider A crawler of vertical communities achieved by GOLANG. Latest stable Release: Version 1.2 (Sep 23, 2014). QQ群号:337344607 Features Concurrent

胡聪 1.8k Dec 2, 2022
Secure-by-default HTTP servers in Go.

go-safeweb DISCLAIMER: This is not an officially supported Google product. go-safeweb is a collection of libraries for writing secure-by-default HTTP

Google 570 Dec 2, 2022
[爬虫框架 (golang)] An awesome Go concurrent Crawler(spider) framework. The crawler is flexible and modular. It can be expanded to an Individualized crawler easily or you can use the default crawl components only.

go_spider A crawler of vertical communities achieved by GOLANG. Latest stable Release: Version 1.2 (Sep 23, 2014). QQ群号:337344607 Features Concurrent

胡聪 1.8k Dec 2, 2022
Python's webbrowser in Go. Simple API for opening web pages on your default browser.

webbrowser webbrowser provides a simple API for opening web pages on your default browser. It's inspired on Python's webbrowser package but lacks some

Carlos Cobo 181 Oct 31, 2022
Build for all Go-supported platforms by default, disable those which you don't want.

bagop Build for all Go-supported platforms by default, disable those which you don't want. Overview bagop is a simple build tool for Go which tries to

Felix Pojtinger 7 Jul 29, 2022
GoPhish by default tips your hand to defenders and security solutions. T

GoPhish by default tips your hand to defenders and security solutions. The container here strips those indicators and makes other changes to hopefully evade detection during operations.

null 103 Nov 16, 2022
Default godoc generator - make your first steps towards better code documentation

godoc-generate Overview godoc-generate is a simple command line tool that generates default godoc comments on all exported types, functions, consts an

Dimitar Petrov 19 Sep 14, 2022
Build for all gccgo-supported platforms by default, disable those which you don't want (bagop with CGo support).

bagccgop Build for all gccgo-supported platforms by default, disable those which you don't want (bagop with CGo support). Overview bagccgop is a simpl

Felix Pojtinger 2 Nov 9, 2022
Tis module used as base fo configuration apps.By default, it expands into the inside of the application.

Tis module used as base fo configuration apps.By default, it expands into the inside of the application. Also, module c reads a dictionary of secrets from the application directory by its AppName and extension json.

LordTor 0 Dec 7, 2021
Caddy: an extensible server platform that uses TLS by default

a project Every site on HTTPS Caddy is an extensible server platform that uses TLS by default. Releases · Documentation · Get Help Menu Features Insta

Blizard 0 Nov 7, 2021