Help us shape the future of Go! Take the 2026 Go Developer Survey

defaults

package module
v1.9.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 12, 2026 License: MIT Imports: 8 Imported by: 986

README

!!! Looking for a new maintainer !!!

defaults

CI 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
    • Nested types
      • map[K1]map[K2]Struct, []map[K1]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:
    • Implementing the defaults.Setter interface, or
    • Implementing encoding.TextUnmarshaler, which takes precedence over defaults.Setter -- the tag is handed to UnmarshalText and SetDefaults is not called
  • Preserves non-initial values from being reset with a default value
    • A field is written only while it still holds its type's zero value. No scalar type can tell an unspecified value from its zero value — an int left alone is 0, a string is "", a bool is false — so a zero the caller set on purpose is indistinguishable from one never set, and the default replaces it.
    • Use a pointer where that distinction matters. nil means unspecified, and a pointer to the zero value is preserved: *bool is the way to let false survive a default:"true".

Usage

package main

import (
	"encoding/json"
	"fmt"
	"math/rand"

	"github.com/creasty/defaults"
)

type Gender string

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

	SliceInt    []int    `default:"[1, 2, 3]"`
	SlicePtr    []*int   `default:"[1, 2, 3]"`
	SliceString []string `default:"[\"a\", \"b\"]"`

	MapNull            map[string]int          `default:"{}"`
	Map                map[string]int          `default:"{\"key1\": 123}"`
	MapOfStruct        map[string]OtherStruct  `default:"{\"Key2\": {\"Foo\":123}}"`
	MapOfPtrStruct     map[string]*OtherStruct `default:"{\"Key3\": {\"Foo\":123}}"`
	MapOfStructWithTag map[string]OtherStruct  `default:"{\"Key4\": {\"Foo\":123}}"`

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

	NoTag    OtherStruct // Recurses into a nested struct by default
	NoOption OtherStruct `default:"-"` // no option
}

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
	}
}

func main() {
	obj := &Sample{}
	if err := defaults.Set(obj); err != nil {
		panic(err)
	}

	out, err := json.MarshalIndent(obj, "", "	")
	if err != nil {
		panic(err)
	}
	fmt.Println(string(out))

	// Output:
	// {
	// 	"Name": "John Smith",
	// 	"Age": 27,
	// 	"Gender": "m",
	// 	"Working": true,
	// 	"SliceInt": [
	// 		1,
	// 		2,
	// 		3
	// 	],
	// 	"SlicePtr": [
	// 		1,
	// 		2,
	// 		3
	// 	],
	// 	"SliceString": [
	// 		"a",
	// 		"b"
	// 	],
	// 	"MapNull": {},
	// 	"Map": {
	// 		"key1": 123
	// 	},
	// 	"MapOfStruct": {
	// 		"Key2": {
	// 			"Hello": "world",
	// 			"Foo": 123,
	// 			"Random": 5577006791947779410
	// 		}
	// 	},
	// 	"MapOfPtrStruct": {
	// 		"Key3": {
	// 			"Hello": "world",
	// 			"Foo": 123,
	// 			"Random": 8674665223082153551
	// 		}
	// 	},
	// 	"MapOfStructWithTag": {
	// 		"Key4": {
	// 			"Hello": "world",
	// 			"Foo": 123,
	// 			"Random": 6129484611666145821
	// 		}
	// 	},
	// 	"Struct": {
	// 		"Hello": "world",
	// 		"Foo": 123,
	// 		"Random": 4037200794235010051
	// 	},
	// 	"StructPtr": {
	// 		"Hello": "world",
	// 		"Foo": 123,
	// 		"Random": 3916589616287113937
	// 	},
	// 	"NoTag": {
	// 		"Hello": "world",
	// 		"Foo": 0,
	// 		"Random": 6334824724549167320
	// 	},
	// 	"NoOption": {
	// 		"Hello": "",
	// 		"Foo": 0,
	// 		"Random": 0
	// 	}
	// }
}

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func CanUpdate

func CanUpdate(v interface{}) bool

CanUpdate returns true when the given value is an initial value of its type

Example
package main

import (
	"fmt"

	"github.com/creasty/defaults"
)

func main() {
	fmt.Println(defaults.CanUpdate(0), defaults.CanUpdate(123))
	fmt.Println(defaults.CanUpdate(""), defaults.CanUpdate("hello"))
}
Output:
true false
true false

func MustSet added in v1.5.1

func MustSet(ptr interface{})

MustSet function is a wrapper of Set function It will call Set and panic if err not equals nil.

func Set

func Set(ptr interface{}) error

Set initializes members in a struct referenced by a pointer. Maps and slices are initialized by `make` and other primitive types are set with default values. `ptr` should be a struct pointer

Example
package main

import (
	"fmt"
	"time"

	"github.com/creasty/defaults"
)

func main() {
	type Server struct {
		Host    string            `default:"localhost"`
		Port    int               `default:"8080"`
		Timeout time.Duration     `default:"30s"`
		Tags    []string          `default:"[\"web\"]"`
		Labels  map[string]string `default:"{\"env\": \"dev\"}"`
	}

	var server Server
	if err := defaults.Set(&server); err != nil {
		panic(err)
	}

	fmt.Printf("%s:%d\n", server.Host, server.Port)
	fmt.Println(server.Timeout)
	fmt.Println(server.Tags, server.Labels)
}
Output:
localhost:8080
30s
[web] map[env:dev]
Example (Nested)
package main

import (
	"fmt"

	"github.com/creasty/defaults"
)

func main() {
	type Retry struct {
		Attempts int `default:"3"`
	}
	type Client struct {
		// A struct is descended into with or without a tag, and a pointer needs one to be
		// allocated at all.
		Retry    Retry
		Fallback *Retry `default:"{}"`
		Disabled *Retry
	}

	var client Client
	if err := defaults.Set(&client); err != nil {
		panic(err)
	}

	fmt.Println(client.Retry.Attempts)
	fmt.Println(client.Fallback.Attempts)
	fmt.Println(client.Disabled == nil)
}
Output:
3
3
true

Types

type Setter

type Setter interface {
	SetDefaults()
}

Setter is an interface for setting default values

Example
package main

import (
	"fmt"
	"time"

	"github.com/creasty/defaults"
)

// Config implements defaults.Setter for ExampleSetter below.
type Config struct {
	Retries int           `default:"3"`
	Backoff time.Duration `default:"-"`
}

// SetDefaults derives a default that a tag cannot express, and CanUpdate keeps it from overriding
// what the caller already provided.
func (c *Config) SetDefaults() {
	if defaults.CanUpdate(c.Backoff) {
		c.Backoff = time.Duration(c.Retries) * time.Second
	}
}

func main() {
	var config Config
	if err := defaults.Set(&config); err != nil {
		panic(err)
	}
	fmt.Println(config.Retries, config.Backoff)

	// A value the caller supplied is left alone.
	custom := Config{Backoff: time.Minute}
	if err := defaults.Set(&custom); err != nil {
		panic(err)
	}
	fmt.Println(custom.Retries, custom.Backoff)
}
Output:
3 3s
3 1m0s

Directories

Path Synopsis
internal
fixture
Package fixture provides types declared outside the test package, so tests can observe how Set behaves across a package boundary.
Package fixture provides types declared outside the test package, so tests can observe how Set behaves across a package boundary.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL