Constructors and exported names
A struct's zero value is like a blank form fresh from the printer. Often you can start filling it in right away. But sometimes a whole section is missing from the form, and there is nowhere to write. Go works the same way: a struct's zero value is not always ready for use. A field of map type is nil in it, and the very first write into it ends in a panic:
package main
type Phonebook struct {
numbers map[string]string
}
func main() {
var book Phonebook
book.numbers["Ann"] = "555-01" // ✗
}panic: assignment to entry in nil mapThe program builds, but at run time it panics at the line with the write: the field numbers is a nil map. Everyone who creates a Phonebook has to remember the make. It is safer when one function creates the struct and fills in every field.
The constructor
A constructor is an ordinary function that creates a value and returns it ready for use. It is like an office counter that hands you a prepared form with every section in place. Go has no special syntax for constructors. By convention such a function is named New plus the type's name:
type Phonebook struct {
numbers map[string]string
}
func NewPhonebook() *Phonebook {
return &Phonebook{numbers: make(map[string]string)}
}
func (p *Phonebook) Set(name, number string) {
p.numbers[name] = number
}The key line here is return &Phonebook{numbers: make(map[string]string)}. Let's take it apart:
make(map[string]string)creates an empty map you can already write to;Phonebook{numbers: …}is a struct literal with the fieldnumbersfilled in;&before the literal creates a new struct and returns its address. It works likenew, but with the fields filled in.
The constructor returns a pointer, a slip with the address of the ready form. Copies of book then copy only the address, so every method changes the same struct.
Calling the constructor
The calling code keeps the pointer from the constructor and calls methods through it:
book := NewPhonebook()
book.Set("Ann", "555-01")
book.Set("Ann", "555-02")
fmt.Println(book.numbers["Ann"], len(book.numbers)) // 555-02 1Let's walk through the example line by line:
book := NewPhonebook()gets a pointer to a struct whose map already exists.- The first
Setstores Ann's number. - The second
Setreplaces it with a new number. fmt.Printlnprints555-02 1: there is one key, and it holds the last number.
Exported names
In Go, the case of a name's first letter sets its visibility. In the form picture, these are the fields anyone may fill in and the internal notes that only the office itself fills in. The rule is the same for functions, types, fields and methods.
A capitalized name
A name that starts with a capital letter is an exported name: other packages can see it. Examples:
fmt.Printlncan be called frommain: its name starts withP;- if
Phonebookis put into a separate package, other packages can callNewPhonebookandSet; - the fields
XandYofPointstart with a capital letter, so other packages can change them.
A lowercase name
A name that starts with a lowercase letter is visible only inside its own package. Other packages cannot reach the field numbers of Phonebook. They cannot fill it in, so they get a working Phonebook only from the constructor.
Inside one package every name is visible, lowercase and capitalized alike. Here the picture parts ways with Go: the "office" is the whole package, not one type.
A private field
Interviewers like to ask: "How do you make a field private in Go?" The answer:
- start the field's name with a lowercase letter;
- Go has no keywords like
private; - visibility is set at the package level, not the type level.
Common mistake
A name from another package is written with a lowercase letter:
fmt.println("hi") // ✗undefined: fmt.println (but have Println)The program does not compile: the fmt package has no name println, only the exported Println. The case of the first letter is part of the name, and the compiler suggests the right name in parentheses.
Key points
- A constructor is an ordinary
NewTfunction that returns a value ready for use. &T{...}creates a struct with its fields filled in and returns its address.- A capitalized name is visible to other packages; a lowercase one only to its own package.
Subscribe to take the course
The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.