In today's post, I will introduce some techniques and methods to set default values in Go structs. We already have some articles about structs, marshal, unmarshal, and constants in structs,... you can refer to these posts to deeply understand how to work with structs in Golang.
Method 1: Using a separate constructor function for the structs
The idea is quite simple. We will create a function that returns a struct with some default value.
package main
import "fmt"
type Student struct {
Name string
School string
Age int
}
// Set default value for a instance
func SetDefault(name string) Student {
st := Student{}
st.Name = name
st.School = "Go LinuxCloud"
st.Age = 25
return st
}
func main() {
defaultStudent := SetDefault("Harry Potter")
fmt.Printf("The default student: %+v\n", defaultStudent)
student := new(Student)
fmt.Printf("The empty student: %+v\n", student)
}
Output:
The default student: {Name:Harry Potter School:Go LinuxCloud Age:25}
The empty student: &{Name: School: Age:0}
Method 2: Using an Init() function
The idea for this method is to create an Init()
function for that struct. The code below shows how we can do that in Golang:
package main
import "fmt"
type Student struct {
Name string
School string
Age int
}
// Init is the main function that initiate the structure, and return it
func (st Student) Init() Student {
st.Name = "Default Value"
st.School = "Go LinuxCloud"
st.Age = 25
return st
}
func main() {
defaultStudent := new(Student).Init()
fmt.Printf("The default student: %+v\n", defaultStudent)
}
Output:
The default student: {Name:Default Value School:Go LinuxCloud Age:25}
Tags offer a method of doing this that enables multiple defaults. Suppose you have the struct below, which has the default tags default0 and default1. We will try to create 2 default structs in the example below:
package main
import (
"fmt"
"reflect"
"strconv"
)
type Student struct {
Name string `default0:"Harry Potter" default1:"Custom Name"`
School string `default0:"GoLinuxCloud" default1:"Google"`
Age int `default0:"3" default1:"42"`
}
func main() {
std1 := &Student{}
Set(std1, "default0")
fmt.Printf("The first default value: %+v\n", std1)
std2 := &Student{}
Set(std2, "default1")
fmt.Printf("The second default value: %+v\n", std2)
}
func setField(field reflect.Value, defaultVal string) error {
if !field.CanSet() {
return fmt.Errorf("Can't set value\n")
}
switch field.Kind() {
case reflect.Int:
if val, err := strconv.ParseInt(defaultVal, 10, 64); err == nil {
field.Set(reflect.ValueOf(int(val)).Convert(field.Type()))
}
case reflect.String:
field.Set(reflect.ValueOf(defaultVal).Convert(field.Type()))
}
return nil
}
func Set(ptr interface{}, tag string) error {
if reflect.TypeOf(ptr).Kind() != reflect.Ptr {
return fmt.Errorf("Not a pointer")
}
v := reflect.ValueOf(ptr).Elem()
t := v.Type()
for i := 0; i < t.NumField(); i++ {
if defaultVal := t.Field(i).Tag.Get(tag); defaultVal != "-" {
if err := setField(v.Field(i), defaultVal); err != nil {
return err
}
}
}
return nil
}
Output:
The first default value: &{Name:Harry Potter School:GoLinuxCloud Age:3}
The second default value: &{Name:Custom Name School:Google Age:42}
Explanation
We will create 2 helper functions: Set() and SetField(). These two functions will iterate all the fields in the struct and set the value in the tag to each field.
Summary
A constructor function can be used to give default values to a struct. Instead of explicitly building a structure, we may use a constructor to give all or some of its members custom default values.
References
https://pkg.go.dev/encoding/json
How to set default values in Go structs - Stack Overflow