How to set default values in Go structs - go

There are multiple answers/techniques to the below question:
How to set default values to golang structs?
How to initialize structs in golang
I have a couple of answers but further discussion is required.

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
}

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

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.

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

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
}

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()

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

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{}),
}
}

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)

Structs
An easy way to make this program better is to use a struct. A struct is a type which contains named fields. For example we could represent a Circle like this:
type Circle struct {
x float64
y float64
r float64
}
The type keyword introduces a new type. It's followed by the name of the type (Circle), the keyword struct to indicate that we are defining a struct type and a list of fields inside of curly braces. Each field has a name and a type. Like with functions we can collapse fields that have the same type:
type Circle struct {
x, y, r float64
}
Initialization
We can create an instance of our new Circle type in a variety of ways:
var c Circle
Like with other data types, this will create a local Circle variable that is by default set to zero. For a struct zero means each of the fields is set to their corresponding zero value (0 for ints, 0.0 for floats, "" for strings, nil for pointers, …) We can also use the new function:
c := new(Circle)
This allocates memory for all the fields, sets each of them to their zero value and returns a pointer. (*Circle) More often we want to give each of the fields a value. We can do this in two ways. Like this:
c := Circle{x: 0, y: 0, r: 5}
Or we can leave off the field names if we know the order they were defined:
c := Circle{0, 0, 5}

type Config struct {
AWSRegion string `default:"us-west-2"`
}

Related

Generic Structs with Go

What is the equivalent of this C# code in Go, how can I build it
class ModelX<T>
{
public T Data { get; set; }
}
ModelX<int>
I have tried something like:
type ModelX<T> struct {
ModelY
Data []T
}
m := ModelX<T>
How to do this? Is that possible?
Starting with Go 1.18, you can define generic types:
type Model[T any] struct {
Data []T
}
A generic type must be instantiated1 when used, and instantiation requires a type parameter list:
func main() {
// passing int as type parameter
modelInt := Model[int]{Data: []int{1, 2, 3}}
fmt.Println(modelInt.Data) // [1 2 3]
// passing string as type parameter
modelStr := Model[string]{Data: []string{"a", "b", "c"}}
fmt.Println(modelStr.Data) // [a b c]
}
More info and common gotchas about instantiations: Go error: cannot use generic type without instantiation
If you declare methods on a generic type, you must repeat the type parameter declaration on the receiver, even if the type parameters are not used in the method scope — in which case you may use the blank identifier _ to make it obvious:
func (m *Model[T]) Push(item T) {
m.Data = append(m.Data, item)
}
// not using the type param in this method
func (m *Model[_]) String() string {
return fmt.Sprint(m.Data)
}
An important detail is that — unlike functions2 —, generic types must always supply all3 type parameters upon instantiation. For example, this type:
type Foo[T any, P *T] struct {
val T
ptr P
}
must be instantiated with both types, even if some of them could be inferred:
func main() {
v := int64(20)
foo := Foo[int64, *int64]{val:v, ptr: &v}
fmt.Println(foo)
}
Playground: https://go.dev/play/p/n2G6l6ozacj
Footnotes:
1: Language specs about instantiations: https://golang.org/ref/spec#Instantiations
2: The quote from the specs is "Calls to parameterized functions may provide a (possibly partial) type argument list, or may omit it entirely if the omitted type arguments are inferrable from the ordinary (non-type) function arguments.". This quote excludes parametrized types
3: in early beta releases, the type param list in generic types could be partial; this feature has been disabled.

How to create a copy of a struct only having interface it implements and it's value

Let's say I have this A struct that implements Setter interface:
type Setter interface {
Set(key string, value string)
}
type A struct {
m map[string]string
}
func (a *A) Set(key string, value string) {
a.m[key] = value
}
And I have one different struct that holds some implementation of Setter interface
type Holder struct {
val Setter
}
h := Holder{
val: &A{ map[string]string{} },
}
What i need is to get a copy of the h.val struct with all values saved.
I have already tried the following solution but it did not work, resulting with panic: assignment to entry in nil map
(We have defined the map when initiallizing h, so by running h.val.Set(k, v) we won't get any errors)
l := reflect.New(
reflect.ValueOf(h.val).Elem().Type(),
).Interface().(Setter)
l.Set("A", "B")
How can I create a copy of a struct without knowing which fields it consists of, only knowing the interface it implements and having it's value in a variable?
p.s. Adding Clone method to Setter interface is not a preferred solution
Adding Clone method to Setter interface is not a preferred solution
in all generality, since only the Setter implementation knows how it should be "cloned", there isn't much choice.
For example : should "cloning" an A struct create a new struct pointing at the same mapping ? or should it duplicate the mapping ?
If your intention is really to clone, you probably want the second, but you can see it will quickly fall outside the scope of a simple reflect operation.
If your code actually only deals with A structs, you may pass explicit A values. You will probably still need a .Clone() method or a Clone(a *A) function.
If your only issue is that a zero value for A is invalid, you can fix Set() :
func (a *A) Set(key string, value string) {
if a.m == nil {
a.m = make(map[string]string)
}
a.m[key] = value
}

How to use runtime.Object to create CRD generic functions in go [duplicate]

I have an interface Model, which is implemented by struct Person.
To get a model instance, I have the following helper functions:
func newModel(c string) Model {
switch c {
case "person":
return newPerson()
}
return nil
}
func newPerson() *Person {
return &Person{}
}
The above approach allows me to return a properly typed Person instance (can easily add new models later with same approach).
When I attempted to do something similar for returning a slice of models, I get an error. Code:
func newModels(c string) []Model {
switch c {
case "person":
return newPersons()
}
return nil
}
func newPersons() *[]Person {
var models []Person
return &models
}
Go complains with: cannot use newPersons() (type []Person) as type []Model in return argument
My goal is to return a slice of whatever model type is requested (whether []Person, []FutureModel, []Terminator2000, w/e). What am I missing, and how can I properly implement such a solution?
This is very similar to a question I just answered: https://stackoverflow.com/a/12990540/727643
The short answer is that you are correct. A slice of structs is not equal to a slice of an interface the struct implements.
A []Person and a []Model have different memory layouts. This is because the types they are slices of have different memory layouts. A Model is an interface value which means that in memory it is two words in size. One word for the type information, the other for the data. A Person is a struct whose size depends on the fields it contains. In order to convert from a []Person to a []Model, you will need to loop over the array and do a type conversion for each element.
Since this conversion is an O(n) operation and would result in a new slice being created, Go refuses to do it implicitly. You can do it explicitly with the following code.
models := make([]Model, len(persons))
for i, v := range persons {
models[i] = Model(v)
}
return models
And as dskinner pointed out, you most likely want a slice of pointers and not a pointer to a slice. A pointer to a slice is not normally needed.
*[]Person // pointer to slice
[]*Person // slice of pointers
Maybe this is an issue with your return type *[]Person, where it should actually be []*Person so to reference that each index of the slice is a reference to a Person, and where a slice [] is in itself a reference to an array.
Check out the following example:
package main
import (
"fmt"
)
type Model interface {
Name() string
}
type Person struct {}
func (p *Person) Name() string {
return "Me"
}
func NewPersons() (models []*Person) {
return models
}
func main() {
var p Model
p = new(Person)
fmt.Println(p.Name())
arr := NewPersons()
arr = append(arr, new(Person))
fmt.Println(arr[0].Name())
}
As Stephen already answered the question and you're a beginner I emphasize on giving advises.
A better way of working with go's interfaces is not to have a constructor returning
the interface as you might be used to from other languages, like java, but to have
a constructor for each object independently, as they implement the interface implicitly.
Instead of
newModel(type string) Model { ... }
you should do
newPerson() *Person { ... }
newPolitician() *Politician { ... }
with Person and Politician both implementing the methods of Model.
You can still use Person or Politician everywhere where a Model
is accepted, but you can also implement other interfaces.
With your method you would be limited to Model until you do a manual conversion to
another interface type.
Suppose I have a Person which implements the method Walk() and a Model implements ShowOff(), the following would not work straight forward:
newModel("person").ShowOff()
newModel("person").Walk() // Does not compile, Model has no method Walk
However this would:
newPerson().ShowOff()
newPerson().Walk()
As others have already answered, []T is a distinct type. I'd just like to add that a simple utility can be used to convert them generically.
import "reflect"
// Convert a slice or array of a specific type to array of interface{}
func ToIntf(s interface{}) []interface{} {
v := reflect.ValueOf(s)
// There is no need to check, we want to panic if it's not slice or array
intf := make([]interface{}, v.Len())
for i := 0; i < v.Len(); i++ {
intf[i] = v.Index(i).Interface()
}
return intf
}
Now, you can use it like this:
ToIntf([]int{1,2,3})
Types T and []T are distinct types and distinct are their methods as well, even when satisfying the same interface. IOW, every type satisfying Model must implement all of the Model's methods by itself - the method receiver can be only one specific type.
Even if Go's implementation allowed this, it's unfortunately unsound: You can't assign a []Person to a variable of type []Model because a []Model has different capabilities. For example, suppose we also have Animal which implements Model:
var people []Person = ...
var models []Model = people // not allowed in real Go
models[0] = Animal{..} // ???
var person Person = people[0] // !!!
If we allow line 2, then line 3 should also work because models can perfectly well store an Animal. And line 4 should still work because people stores Persons. But then we end up with a variable of type Person holding an Animal!
Java actually allows the equivalent of line 2, and it's widely considered a mistake. (The error is caught at run time; line 3 would throw an ArrayStoreException.)

Restore type information after passing through function as "interface {}"?

I'm running into a slight architectural problem with Golang right now that's causing me to copy/paste a bit more code than I'd prefer. I feel like there must be a solution, so please let me know if this is perhaps possible:
When I pass things through an interface {}-typed function parameter, I start getting errors such as "expected struct or slice", etc. ... even though what I passed was previously a struct or a slice. I realize that I could manually convert these to another type after receiving them in that function, but then that become tedious in instances such as this:
local interface type *interface {} can only be decoded from remote
interface type; received concrete type
... In this case, the receiving function seems like it'd need to be hard-coded to convert all interface {} items back to their respective original types in order to work properly, because the receiving function needs to know the exact type in order to process the item correctly.
Is there a way to dynamically re-type Golang interface {} typed variables back to their original type? Something like this, How to I convert reflect.New's return value back to the original type ... maybe?
EDIT: To clarify, basically, I'm passing &out to a function and it needs to be its original type by the time it reaches another inner function call.
Example code:
// NOTE: This is sort of pseudo-Golang code, not meant to be compiled or taken too seriously.
func PrepareTwoDifferentThings(keyA string, keyB string) {
var somethingA TypeA;
var somethingB TypeB;
loadFromCache(keyA, &somethingA, nil);
loadFromCache(keyB, &somethingB, nil);
fmt.Printf("Somethings: %v, %v", somethingA, somethingB);
}
func loadFromCache(key string, isNew, out interface {}, saveNewData interface {}) {
if err := cache.load(key, &out); err!=nil { // NOTE: Current issue is that this expects "&out" to be `TypeA`/`TypeB` not "interface {}", but I don't want to copy and paste this whole function's worth of code or whatever.
panic("oh no!");
}
if (saveNewData!=nil) {
cache.save(key, saveNewData); // This doesn't seem to care if "saveNewData" is "interface {}" when saving, but later cache fetches above using the "load()" method to an "interface {}"-typed `&out` parameter throw an exception that the "interface {}" type on `&out` does not match the original when it was saved here (`TypeA`/`TypeB`).
}
}
To change the type of an interface into its rightful type, you can use type assertions:
package main
import r "reflect"
type A struct {
Name string
}
func main() {
// No pointer
aa := A{"name"}
var ii interface{} = aa
bb := ii.(A)
// main.A
// Pointer
a := &A{"name"}
var i interface{} = a
b := *i.(*A)
// main.A
c := i.(*A)
// *main.A
d := r.Indirect(r.ValueOf(i)).Interface().(A)
// main.A
}
Playground 1
When using type assertions, you have to know the underlying type of your interface. In Go, there is no way to use type assertion with a dynamic type. reflect.Type is not a type, it's an interface representing a type. So no, you can't use it this way.
If you have several type possibilities, the solution is the type switch:
package main
import "fmt"
type TypeA struct {
A string
}
type TypeB struct {
B string
}
func doSomethingA(t TypeA) {
fmt.Println(t.A)
}
func doSomethingB(t TypeB) {
fmt.Println(t.B)
}
func doSomething(t interface{}) {
switch t := t.(type) {
case TypeA:
doSomethingA(t)
case TypeB:
doSomethingB(t)
default:
panic("Unrecognized type")
}
}
func main() {
a := TypeA{"I am A"}
b := TypeB{"I am B"}
doSomething(a)
// I am A
doSomething(b)
// I am B
}
Playground 2
It turns out that using JSON instead of Gob for serialization avoids the error that I was encountering entirely. Other functions can handle passing into interfaces, etc.

slice of struct != slice of interface it implements?

I have an interface Model, which is implemented by struct Person.
To get a model instance, I have the following helper functions:
func newModel(c string) Model {
switch c {
case "person":
return newPerson()
}
return nil
}
func newPerson() *Person {
return &Person{}
}
The above approach allows me to return a properly typed Person instance (can easily add new models later with same approach).
When I attempted to do something similar for returning a slice of models, I get an error. Code:
func newModels(c string) []Model {
switch c {
case "person":
return newPersons()
}
return nil
}
func newPersons() *[]Person {
var models []Person
return &models
}
Go complains with: cannot use newPersons() (type []Person) as type []Model in return argument
My goal is to return a slice of whatever model type is requested (whether []Person, []FutureModel, []Terminator2000, w/e). What am I missing, and how can I properly implement such a solution?
This is very similar to a question I just answered: https://stackoverflow.com/a/12990540/727643
The short answer is that you are correct. A slice of structs is not equal to a slice of an interface the struct implements.
A []Person and a []Model have different memory layouts. This is because the types they are slices of have different memory layouts. A Model is an interface value which means that in memory it is two words in size. One word for the type information, the other for the data. A Person is a struct whose size depends on the fields it contains. In order to convert from a []Person to a []Model, you will need to loop over the array and do a type conversion for each element.
Since this conversion is an O(n) operation and would result in a new slice being created, Go refuses to do it implicitly. You can do it explicitly with the following code.
models := make([]Model, len(persons))
for i, v := range persons {
models[i] = Model(v)
}
return models
And as dskinner pointed out, you most likely want a slice of pointers and not a pointer to a slice. A pointer to a slice is not normally needed.
*[]Person // pointer to slice
[]*Person // slice of pointers
Maybe this is an issue with your return type *[]Person, where it should actually be []*Person so to reference that each index of the slice is a reference to a Person, and where a slice [] is in itself a reference to an array.
Check out the following example:
package main
import (
"fmt"
)
type Model interface {
Name() string
}
type Person struct {}
func (p *Person) Name() string {
return "Me"
}
func NewPersons() (models []*Person) {
return models
}
func main() {
var p Model
p = new(Person)
fmt.Println(p.Name())
arr := NewPersons()
arr = append(arr, new(Person))
fmt.Println(arr[0].Name())
}
As Stephen already answered the question and you're a beginner I emphasize on giving advises.
A better way of working with go's interfaces is not to have a constructor returning
the interface as you might be used to from other languages, like java, but to have
a constructor for each object independently, as they implement the interface implicitly.
Instead of
newModel(type string) Model { ... }
you should do
newPerson() *Person { ... }
newPolitician() *Politician { ... }
with Person and Politician both implementing the methods of Model.
You can still use Person or Politician everywhere where a Model
is accepted, but you can also implement other interfaces.
With your method you would be limited to Model until you do a manual conversion to
another interface type.
Suppose I have a Person which implements the method Walk() and a Model implements ShowOff(), the following would not work straight forward:
newModel("person").ShowOff()
newModel("person").Walk() // Does not compile, Model has no method Walk
However this would:
newPerson().ShowOff()
newPerson().Walk()
As others have already answered, []T is a distinct type. I'd just like to add that a simple utility can be used to convert them generically.
import "reflect"
// Convert a slice or array of a specific type to array of interface{}
func ToIntf(s interface{}) []interface{} {
v := reflect.ValueOf(s)
// There is no need to check, we want to panic if it's not slice or array
intf := make([]interface{}, v.Len())
for i := 0; i < v.Len(); i++ {
intf[i] = v.Index(i).Interface()
}
return intf
}
Now, you can use it like this:
ToIntf([]int{1,2,3})
Types T and []T are distinct types and distinct are their methods as well, even when satisfying the same interface. IOW, every type satisfying Model must implement all of the Model's methods by itself - the method receiver can be only one specific type.
Even if Go's implementation allowed this, it's unfortunately unsound: You can't assign a []Person to a variable of type []Model because a []Model has different capabilities. For example, suppose we also have Animal which implements Model:
var people []Person = ...
var models []Model = people // not allowed in real Go
models[0] = Animal{..} // ???
var person Person = people[0] // !!!
If we allow line 2, then line 3 should also work because models can perfectly well store an Animal. And line 4 should still work because people stores Persons. But then we end up with a variable of type Person holding an Animal!
Java actually allows the equivalent of line 2, and it's widely considered a mistake. (The error is caught at run time; line 3 would throw an ArrayStoreException.)

Resources