Skip to content
Theory · Structs and methods · lesson 7 of 11

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:

GO
package main

type Phonebook struct {
    numbers map[string]string
}

func main() {
    var book Phonebook
    book.numbers["Ann"] = "555-01" // ✗
}
TEXT
panic: assignment to entry in nil map

The 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:

GO
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 field numbers filled in;
  • & before the literal creates a new struct and returns its address. It works like new, 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:

GO
book := NewPhonebook()
book.Set("Ann", "555-01")
book.Set("Ann", "555-02")
fmt.Println(book.numbers["Ann"], len(book.numbers)) // 555-02 1

Let's walk through the example line by line:

  1. book := NewPhonebook() gets a pointer to a struct whose map already exists.
  2. The first Set stores Ann's number.
  3. The second Set replaces it with a new number.
  4. fmt.Println prints 555-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.Println can be called from main: its name starts with P;
  • if Phonebook is put into a separate package, other packages can call NewPhonebook and Set;
  • the fields X and Y of Point start 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:

GO
fmt.println("hi") // ✗
TEXT
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 NewT function 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.

Sign in another way