Constructor Patterns
Building idiomatic Go constructors
Constructor Patterns is a free Go Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Go Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Why Constructors?
Go has no new keyword for types and no class constructors. The convention is a function named New... that validates inputs and returns an initialized value or pointer.
Simple New Function
Return a pointer to ensure the caller works with a shared instance:
package main
import "fmt"
type Server struct {
Host string
Port int
}
func NewServer(host string, port int) *Server {
return &Server{Host: host, Port: port}
}
func main() {
s := NewServer("localhost", 8080)
fmt.Println(s.Host, s.Port)
}Validation in Constructors
Constructors are a good place to validate inputs and return an error:
package main
import ("errors"; "fmt")
type Config struct{ Workers int }
func NewConfig(workers int) (*Config, error) {
if workers < 1 {
return nil, errors.New("workers must be >= 1")
}
return &Config{Workers: workers}, nil
}
func main() {
c, err := NewConfig(4)
fmt.Println(c, err)
}Functional Options Pattern
The functional options pattern allows optional configuration without breaking the API:
package main
import "fmt"
type Server struct{ host string; port int; timeout int }
type Option func(*Server)
func WithPort(p int) Option { return func(s *Server) { s.port = p } }
func WithTimeout(t int) Option { return func(s *Server) { s.timeout = t } }
func NewServer(host string, opts ...Option) *Server {
s := &Server{host: host, port: 8080, timeout: 30}
for _, o := range opts { o(s) }
return s
}
func main() {
s := NewServer("localhost", WithPort(9090), WithTimeout(60))
fmt.Println(s.port, s.timeout)
}Builder Pattern
For complex objects, the builder pattern chains setter methods and returns the result:
package main
import "fmt"
type QueryBuilder struct{ table, where string; limit int }
func (q *QueryBuilder) Table(t string) *QueryBuilder { q.table = t; return q }
func (q *QueryBuilder) Where(w string) *QueryBuilder { q.where = w; return q }
func (q *QueryBuilder) Limit(n int) *QueryBuilder { q.limit = n; return q }
func (q *QueryBuilder) Build() string {
return fmt.Sprintf("SELECT * FROM %s WHERE %s LIMIT %d", q.table, q.where, q.limit)
}
func main() {
sql := (&QueryBuilder{}).Table("users").Where("age>18").Limit(10).Build()
fmt.Println(sql)
}Returning Value vs Pointer
Return a value when the struct is small and immutable; return a pointer when the struct is large, mutable, or implements interfaces:
- Small config structs → value
- Stateful objects (server, client, pool) → pointer
- If implementing an interface with pointer receivers → pointer
Default Values Pattern
Use a defaults function or struct literal to set sensible defaults before applying options:
package main
import "fmt"
type Cache struct{ maxSize int; ttlSecs int }
func defaultCache() Cache { return Cache{maxSize: 100, ttlSecs: 300} }
func NewCache(opts ...func(*Cache)) *Cache {
c := defaultCache()
for _, o := range opts { o(&c) }
return &c
}
func main() {
c := NewCache(func(c *Cache) { c.maxSize = 500 })
fmt.Println(c.maxSize, c.ttlSecs) // 500 300
}Singleton Pattern
Use sync.Once to initialize a shared resource exactly once:
package main
import ("fmt"; "sync")
type DB struct{ DSN string }
var (
instance *DB
once sync.Once
)
func GetDB(dsn string) *DB {
once.Do(func() { instance = &DB{DSN: dsn} })
return instance
}
func main() {
db1 := GetDB("postgres://...")
db2 := GetDB("ignored")
fmt.Println(db1 == db2) // true
}Testing Constructors
Constructors that return errors are easy to test:
package main
import ("errors"; "fmt")
type Pool struct{ size int }
func NewPool(size int) (*Pool, error) {
if size <= 0 { return nil, errors.New("size must be positive") }
return &Pool{size: size}, nil
}
func main() {
_, err := NewPool(-1)
fmt.Println(err) // size must be positive
p, _ := NewPool(5)
fmt.Println(p.size) // 5
}Avoid init()
init() functions run automatically and are hard to test. Prefer explicit constructors that return errors over implicit initialization in init().
Quick Check
What does the functional options pattern achieve?
Recap: Constructor Patterns
Key takeaways:
- Use
New...functions as constructors - Return errors for validation failures
- Functional options for flexible optional config
- Builder pattern for complex query/config objects
- Prefer explicit constructors over
init()
Practice Prompt
Implement a NewHTTPClient constructor using functional options. Support WithTimeout, WithBaseURL, and WithMaxRetries options.
Frequently asked questions
Is the “Constructor Patterns” lesson free?
Yes — the full text of “Constructor Patterns” is free to read here on the web, and the Go Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Go Academy course, upgrade to CoddyKit PRO.
What will I learn in “Constructor Patterns”?
Building idiomatic Go constructors You practise Go Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Go Academy?
No prior experience is required. Go Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Constructor Patterns” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Go Academy lesson?
Yes. Every Go Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Defining and Using Structs
- Methods on Structs
- Constructor Patterns
- Anonymous Structs and Composition