262

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.

Prateek
  • 6,644
  • 6
  • 22
  • 26
  • 2
    Related: [How to make sure that a method is used after an object is created in golang?](http://stackoverflow.com/questions/36826232/how-to-make-sure-that-a-method-is-used-after-an-object-is-created-in-golang) – icza May 10 '16 at 10:51
  • 1
    @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. – Prateek May 11 '16 at 06:12
  • 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,. – Duncan Jones Sep 11 '17 at 12:24

9 Answers9

156

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
}
Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
vodolaz095
  • 6,680
  • 4
  • 27
  • 42
  • 18
    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. – Prateek May 10 '16 at 10:15
  • 1
    @Prateek it's either this or use an interface, which would be ugly and overcomplicated. – OneOfOne May 10 '16 at 22:50
  • 67
    @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`. – Amit Kumar Gupta May 11 '16 at 06:03
  • Worth Trying. Still wondering if the struct variable will be accessible directly. Will check it out. Thanks !! – Prateek May 11 '16 at 06:05
  • @Amit, I have mention an extension to this in my answer - which recommends to make use of interface as a return value – Prateek May 11 '16 at 11:24
  • 3
    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. – edam Mar 28 '18 at 10:31
  • Shouldn't you return &something with return type *Something as a good practice? – Simon Apr 26 '18 at 19:34
  • To Value add Amit's one, It will be better to go with singleton instead of generating the struct every time – M. Gopal Oct 11 '18 at 13:34
  • 4
    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 – Juliatzin Nov 21 '19 at 12:51
  • @edam how often does that come up? Do any of the stdlib functions do this for user defined types? – jdizzle Nov 19 '21 at 11:38
  • @AmitKumarGupta neat idea but making the type private means the receiver cannot use the type in any function calls (unless the receiver is in same package of course). So not a long-term solution (sooner or later you will have to expose it). – Oliver Nov 29 '22 at 22:44
106
  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.

Profilüfter
  • 81
  • 2
  • 12
Prateek
  • 6,644
  • 6
  • 22
  • 26
  • 7
    This is now a broken link (404): http://joneisen.tumblr.com/post/53695478114/golang-and-default-values – Victor Zamanian Feb 28 '17 at 12:37
  • 5
    It's available in the [wayback machine](https://web.archive.org/web/20160818125551/https://joneisen.tumblr.com/post/53695478114/golang-and-default-values). – n8henrie May 26 '17 at 19:49
  • 1
    FWIW, I think it is 'Option 3' - at least in the wayback machine link. (There is no 'Option 5', there). – decimus phostle Mar 07 '18 at 19:10
  • 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." – starriet Feb 28 '22 at 16:47
  • Here's a problem I ran into with this approach. ---- In the New() function you will have to add a parameter for every field in the struct, and if you have many fields this becomes cumbersome very fast for callers of New(). Obviously you can't pass an Options struct as an argument because then you end up with the same problem we are trying to solve. ---- Instead I opted to have no parameters to New(), it simply will return the struct with custom default values. The idea was that callers call New() and then set the fields after. But now since it's the interface they can't do that. – kebab-case Jul 21 '22 at 23:29
60

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.

wolfson109
  • 898
  • 6
  • 10
  • Do you then need "Candidate" to repeat "Name string" in the interface if you want "c.Name" to be accessible? – Eric Burel Oct 03 '22 at 15:32
  • Having `Name` and `Votes` upper-cased fields is confusing here. They might be useful for json.Marshal or similar reflect-based operations, but for normal access they are as good as lowercase fields. The `interface` cannot export fields, only methods (i.e. it *needs* methods to be usable). – kubanczyk Oct 23 '22 at 10:17
44

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

Mike Chirico
  • 3,381
  • 1
  • 23
  • 20
  • 1
    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 (https://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. – Nordes Feb 04 '20 at 02:21
  • 4
    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. – ton Apr 22 '21 at 12:45
6

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
}
Yurkol
  • 1,414
  • 1
  • 19
  • 28
4

What about making something like this:

// Card is the structure we work with
type Card struct {
    Html        js.Value
    DefaultText string `default:"html"` // this only works with strings
}

// Init is the main function that initiate the structure, and return it
func (c Card) Init() Card {
    c.Html = Document.Call("createElement", "div")
    return c
}

Then call it as:

c := new(Card).Init()
Hasan A Yousef
  • 22,789
  • 24
  • 132
  • 203
3

I found this thread very helpful and educational. The other answers already provide good guidance, but I wanted to summarize my takeaways with an easy to reference (i.e. copy-paste) approach:

package main

import (
    "fmt"
)

// Define an interface that is exported by your package.
type Foo interface {
  GetValue() string // A function that'll return the value initialized with a default.
  SetValue(v string) // A function that can update the default value.
}

// Define a struct type that is not exported by your package.
type foo struct {
  value string
}

// A factory method to initialize an instance of `foo`,
// the unexported struct, with a default value.
func NewFoo() Foo {
  return &foo{
    value: "I am the DEFAULT value.",
  }
}

// Implementation of the interface's `GetValue`
// for struct `foo`.
func (f *foo) GetValue() string {
  return f.value
}

// Implementation of the interface's `SetValue`
// for struct `foo`.
func (f *foo) SetValue(v string) {
  f.value = v
}

func main() {
  f := NewFoo()
  fmt.Printf("value: `%s`\n", f.GetValue())
  f.SetValue("I am the UPDATED value.")
  fmt.Printf("value: `%s`\n", f.GetValue())
}
Olshansky
  • 5,904
  • 8
  • 32
  • 47
  • 1
    Just one note on this example: Go discourages putting Get into the getter's name. Instead your Foo interface could declare `Value() string` and `SetValue(string)`. See https://go.dev/doc/effective_go#Getters – bestbeforetoday Nov 16 '22 at 16:24
1

One way to do that is:

// declare a type
type A struct {
    Filed1 string
    Field2 map[string]interface{}
}

So whenever you need a new variable of your custom defined type just call the NewA function also you can parameterise the function to optionally assign the values to the struct fields

func NewA() *A {
    return &A{
        Filed1: "",
        Field2: make(map[string]interface{}),
    }
}
Dipto Mondal
  • 624
  • 1
  • 4
  • 14
-1

for set default values in Go structs we use anonymous struct:

Person := struct {
    name      string
    age       int
    city      string
}{
    name:      "Peter",
    age:        21,
    city:      "Noida",
}

fmt.Println(Person)

Abhibgn
  • 9
  • 1