How to set default values in Go structs

259,218

Solution 1

  1. Force a method to get the struct (the constructor way).

    From this post:

    A good design is to make your type unexported, but provide an exported constructor function like NewMyType() in which you can properly initialize your struct / type. Also return an interface type and not a concrete type, and the interface should contain everything others want to do with your value. And your concrete type must implement that interface of course.

    This can be done by simply making the type itself unexported. You can export the function NewSomething and even the fields Text and DefaultText, but just don't export the struct type something.

  2. Another way to customize it for you own module is by using a Config struct to set default values (Option 5 in the link). Not a good way though.

Solution 2

One possible idea is to write separate constructor function

//Something is the structure we work with
type Something struct {
     Text string 
     DefaultText string 
} 
// NewSomething create new instance of Something
func NewSomething(text string) Something {
   something := Something{}
   something.Text = text
   something.DefaultText = "default text"
   return something
}

Solution 3

One problem with option 1 in answer from Victor Zamanian is that if the type isn't exported then users of your package can't declare it as the type for function parameters etc. One way around this would be to export an interface instead of the struct e.g.

package candidate
// Exporting interface instead of struct
type Candidate interface {}
// Struct is not exported
type candidate struct {
    Name string
    Votes uint32 // Defaults to 0
}
// We are forced to call the constructor to get an instance of candidate
func New(name string) Candidate {
    return candidate{name, 0}  // enforce the default value here
}

Which lets us declare function parameter types using the exported Candidate interface. The only disadvantage I can see from this solution is that all our methods need to be declared in the interface definition, but you could argue that that is good practice anyway.

Solution 4

There is a way of doing this with tags, which allows for multiple defaults.

Assume you have the following struct, with 2 default tags default0 and default1.

type A struct {
   I int    `default0:"3" default1:"42"`
   S string `default0:"Some String..." default1:"Some Other String..."`
}

Now it's possible to Set the defaults.

func main() {

ptr := &A{}

Set(ptr, "default0")
fmt.Printf("ptr.I=%d ptr.S=%s\n", ptr.I, ptr.S)
// ptr.I=3 ptr.S=Some String...

Set(ptr, "default1")
fmt.Printf("ptr.I=%d ptr.S=%s\n", ptr.I, ptr.S)
// ptr.I=42 ptr.S=Some Other String...
}

Here's the complete program in a playground.

If you're interested in a more complex example, say with slices and maps, then, take a look at creasty/defaultse

Solution 5

From https://golang.org/doc/effective_go.html#composite_literals:

Sometimes the zero value isn't good enough and an initializing constructor is necessary, as in this example derived from package os.

    func NewFile(fd int, name string) *File {
      if fd < 0 {
        return nil
      }
      f := new(File)
      f.fd = fd
      f.name = name
      f.dirinfo = nil
      f.nepipe = 0
      return f
}
Share:
259,218

Related videos on Youtube

Prateek
Author by

Prateek

Java is an ocean and I want to explore all of its corners. Also interested in DIY &amp; Productivity hacks that help in reducing the work/time taken. Learning my way through new technologies - Go, Node.js

Updated on January 20, 2022

Comments

  • Prateek
    Prateek over 2 years

    There are multiple answers/techniques to the below question:

    1. How to set default values to golang structs?
    2. How to initialize structs in golang

    I have a couple of answers but further discussion is required.

    • icza
      icza about 8 years
    • Prateek
      Prateek about 8 years
      @icza You answer does give provide a way to do it but going by the Question Title, it is in no way similar or searchable since it is a very specific question. I will add the link in my answer though.
    • Duncan Jones
      Duncan Jones almost 7 years
      There are two questions here, pick one. Assuming you opt for the first question (as per question title), please be more specific about your prior research and where your other answers require more discusssion,.
  • Prateek
    Prateek about 8 years
    Yes, this is one of the ways that I have also mentioned in my answer but there is no way we can force anyone to use this function only.
  • OneOfOne
    OneOfOne about 8 years
    @Prateek it's either this or use an interface, which would be ugly and overcomplicated.
  • Amit Kumar Gupta
    Amit Kumar Gupta about 8 years
    @Prateek yes, you can force people to use this constructor if you simply make the type itself unexported. You can export the function NewSomething and even the fields Text and DefaultText, but just don't export the struct type something.
  • Prateek
    Prateek about 8 years
    Worth Trying. Still wondering if the struct variable will be accessible directly. Will check it out. Thanks !!
  • Prateek
    Prateek about 8 years
    @Amit, I have mention an extension to this in my answer - which recommends to make use of interface as a return value
  • Victor Zamanian
    Victor Zamanian over 7 years
  • n8henrie
    n8henrie about 7 years
    It's available in the wayback machine.
  • decimus phostle
    decimus phostle over 6 years
    FWIW, I think it is 'Option 3' - at least in the wayback machine link. (There is no 'Option 5', there).
  • edam
    edam over 6 years
    The problem is worse... if a third party (library, for example) is used to instantiate your struct (via reflect.New(), for example), it couldn't be expected to know about your specially-named factory function. In that case, and short of the language itself being changed, only an interface (which the library could check for) would do, I think.
  • Simon
    Simon about 6 years
    Shouldn't you return &something with return type *Something as a good practice?
  • markeissler
    markeissler almost 6 years
    This is incorrect. At best, you could set a tag value on that field and then get to its value with reflection but even with this the syntax is incorrect (missing back ticks) and you'd only be able to set a default value for a string type. If you have some insight as to what this example is referring to specifically please add a link to refer to.
  • M. Gopal
    M. Gopal over 5 years
    To Value add Amit's one, It will be better to go with singleton instead of generating the struct every time
  • Juliatzin
    Juliatzin over 4 years
    It is good to set default, but sometimes, I might want to override default. In this case, I won't be able to initialize a struct with a value that is not the default. a little annoying for me
  • Nordes
    Nordes over 4 years
    Thank's a lot! I started to write the same code as the library suggested and came across this post. It does exactly what you expect (github.com/creasty/defaults). If you have no value it sets the default, but if you assigned a value to your variable, then it's going to not assign the default. It works pretty well with the yaml.v2 library.
  • ton
    ton about 3 years
    This is a nice alternative, but it's not from golang. You have a generic constructor that use reflections. A real default value would be set automatically on every new struct instance.
  • John Isaac
    John Isaac over 2 years
    @edam how often does that come up? Do any of the stdlib functions do this for user defined types?
  • starriet
    starriet over 2 years
    The first quote has been modified to: "You may choose to make your type unexported, and provide an exported constructor function like NewMyType() in which you can properly initialize your struct / type. ... you can stop worrying about improper initialization."