Allocating and initializing Go structs can be tricky for newcomers. Consider this example:
import "sync" type SyncMap struct { lock *sync.RWMutex hm map[string]string } func (m *SyncMap) Put(k, v string) { m.lock.Lock() defer m.lock.Unlock() m.hm[k] = v } func main() { sm := new(SyncMap) sm.Put("Test", "Test") }
This code will panic with a nil pointer exception because lock and hm are not initialized.
To address this, the following workaround can be used:
func (m *SyncMap) Init() { m.hm = make(map[string]string) m.lock = new(sync.RWMutex) } func main() { sm := new(SyncMap) sm.Init() sm.Put("Test", "Test") }
But this adds unnecessary boilerplate.
A cleaner approach is to use a constructor function to initialize the struct. A constructor is a function that returns an initialized instance of a struct. For example:
func NewSyncMap() *SyncMap { return &SyncMap{hm: make(map[string]string)} }
This constructor initializes the hm field, and returns a pointer to the newly created SyncMap instance.
func main() { sm := NewSyncMap() sm.Put("Test", "Test") }
Now, the code initializes the struct correctly without any boilerplate.
The constructor pattern can also be used to initialize multiple fields, start goroutines, or register finalizers for the struct. For example:
func NewSyncMap() *SyncMap { sm := SyncMap{ hm: make(map[string]string), foo: "Bar", } runtime.SetFinalizer(sm, (*SyncMap).stop) go sm.backend() return &sm }
This constructor initializes both hm and foo fields, starts a goroutine for backend(), and registers a finalizer to run the stop() method when the SyncMap instance is garbage collected.
The above is the detailed content of How Can the Constructor Pattern Solve Go Struct Initialization Problems?. For more information, please follow other related articles on the PHP Chinese website!