The reason I have this question is that I often make mistakes that I forgot to specify a value to a struct's field, then the compiler is fine, but the zero value causes bugs.
Here is an example. Say I have a type Foo
defined like this in a package:
package types
type Foo struct {
RequiredField1 string
RequiredField2 string
}
It is exposed and has 2 fields that I'd like both of them to be specified when the Foo
struct is created.
Then I can import and use it in my main function like this:
package main
import (
"github.com/foo/bar/types"
)
func main() {
f := &Foo{
RequiredField1: "fff",
}
fmt.Printf("f.RequiredField2: %v", f.RequiredField2)
}
This causes a bug because I forgot to specify RequiredField2
which is required. And I often make this kind of bugs :p
Now, in order to leverage the compile and prevent this mistake, I made a constructor function for Foo
and asks for the required values.
func NewFoo(field1 string, field2 string) *Foo {
return &Foo{Field1: field1, Field2: field2}
}
So that if I forgot to pass field2
, the compiler won't compile my code:
func main() {
f := NewFoo("foo")
fmt.Printf("f.Field2: %v", f.Field2)
}
The build will fail:
./prog.go:18:13: not enough arguments in call to NewFoo
have (string)
want (string, string)
Now the question is: how to stop the foreign callers (callers from other namespaces) from calling the default constructor of Foo
, that is &Foo
, and force them to use the NewFoo
?
If I can, then I'm safe since NewFoo is the only way to create the Foo
type and the compiler helps me ensure all fields are present when calling it.