Start learning free

LESSON 181 OF 338 · OBJECT-ORIENTED PROGRAMMING

Creating Objects in Go: Struct Values and Pointers

Lesson Read the full explanation

TL ; DR:

  • An object is an instance of a struct type — a real, usable value made from the blueprint.


  • In Go, you create a value of a struct type just by declaring it. No new keyword needed:

    var rex Dog
    

  • Each declaration creates a separate value, even if they all come from the same struct type.



Full lesson:

In the previous lesson you defined the Dog struct — the blueprint. But a blueprint isn't a dog. To get an actual dog you can interact with, you need to create an instance of the struct. An instance is also called an object.


Value-type objects

The simplest way to create an object in Go is to declare it like a regular variable:

var rex Dog

This creates a Dog value named rex. All fields are initialized to their zero values automatically. Notice there's no new keyword — that's not required for value-type struct variables in Go.


Many objects from one struct

You can declare as many Dog values as you want, and each one is independent:

var rex Dog
var buddy Dog
var luna Dog

rex, buddy, and luna are all Dog values, but they're different objects living at different memory addresses. Modifying one won't affect the others.


Pointer allocation (advanced — not used here)

Go also has new, but it returns a pointer to a zeroed struct:

rex := new(Dog)

Don't use this style for these lessons — value-type variables are simpler and Go's garbage collector handles cleanup automatically.


Your task

The Dog struct is already defined for you. Below it, declare three Dog values named rex, buddy, and luna. The pre-filled validation will print one line per dog you've successfully created:

rex exists
buddy exists
luna exists
STEP 1 OF 3
    Ctrl + Enter to check

    GO · OBJECT-ORIENTED PROGRAMMING

    Creating Objects in Go, explained

    Objects are struct values

    A struct type is a blueprint, and an object (an instance) is an actual value made from it. Go has no new keyword in the sense of other languages, and creating an object takes no ceremony. There are three common ways, and the lesson's exercise uses the third.

    Three ways to create one

    Declare a variable

    var rex Dog
    

    This creates a Dog value named rex. Every field starts at its zero value: "" for strings, 0 for numbers, false for booleans. With the empty Dog of this chapter there are no fields yet, but the variable exists and is ready to use.

    Write a struct literal

    rex := Dog{}
    

    A composite literal builds the value and := declares the variable, inferring its type. Once the struct has fields, you set them inside the braces: Dog{name: "Rex"}.

    Take a pointer

    rex := &Dog{}
    

    Putting & in front of the literal gives you a pointer to a new Dog, with type *Dog. The built-in new(Dog) does the same: it returns a *Dog pointing at a zeroed value. Go does not make you free anything, because the garbage collector reclaims values that nothing refers to any more.

    Values and pointers behave differently

    A variable of type Dog holds the struct itself. Assigning it to another variable copies it. A variable of type *Dog holds the address of a struct, so copying the pointer gives two names for one object.

    type Dog struct {
        name string
    }
    
    func main() {
        a := Dog{name: "A"}
        b := a // a copy
        b.name = "B"
        fmt.Println(a.name, b.name) // A B
    
        p := &a // a pointer to a
        p.name = "Z"
        fmt.Println(a.name) // Z
    }
    

    This program prints A B and then Z. Changing the copy left a alone, while changing through the pointer changed a. Notice that p.name works on a pointer without any dereferencing syntax: Go follows the pointer for you.

    Separate declarations also give separate objects. var rex Dog and var buddy Dog, or two calls of &Dog{}, each make an independent value, and changing the fields of one does not touch the other.

    The lesson's exercise

    The exercise asks for three dogs named rex, buddy and luna. The code below them tests each one with != nil, and that test decides which form to use. A plain Dog value can never be compared with nil, because a struct is not a pointer, so the code would not compile. A *Dog can be, and a pointer produced by &Dog{} is never nil.

    1. Create rex with rex := &Dog{}. The literal allocates a new Dog, and & gives its address.
    2. Create buddy the same way. Each literal allocates a separate value, independent of rex.
    3. Create luna the same way, which shows that one type can produce any number of values.
    type Dog struct {}
    
    
    
    func mainFunction() {
        rex := &Dog{}
        buddy := &Dog{}
        luna := &Dog{}
    
        if rex != nil {
            fmt.Println("rex exists")
        }
        if buddy != nil {
            fmt.Println("buddy exists")
        }
        if luna != nil {
            fmt.Println("luna exists")
        }
    }
    

    The output is one line per dog:

    rex exists
    buddy exists
    luna exists
    

    The nil checks are always true here, because nothing in the program can make these pointers nil. They are in the lesson only to show that the variables hold objects. In real code you check for nil on pointers that came from somewhere else, such as a lookup that may find nothing.

    Common mistakes

    • Comparing a struct value with nil. Only pointers, slices, maps, channels, functions and interfaces can be nil. A Dog value always exists.
    • Using a nil pointer. var rex *Dog declares a pointer that is nil, with no Dog behind it. Reading a field through it stops the program with a nil pointer dereference panic.
    • Forgetting that assignment copies. Passing a Dog to a function gives the function its own copy, so changes inside do not reach the caller. Pass a *Dog if the function should change the original.
    • Leaving a declared variable unused. Go will not compile a function with an unused local variable.

    Key takeaways

    • You create an object by declaring a variable or writing a composite literal.
    • Fields start at their zero values.
    • &Dog{} and new(Dog) give a *Dog, which can be compared with nil.
    • Copying a struct value copies its fields, while copying a pointer shares the object.
    Keep going with GoAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free