new and composite literals
Three ways to get a pointer in Go. Two you will type constantly; one you will see in print occasionally and probably never write.
Way 1: take the address of an existing variable
You already know this from Lesson 1:
x := 42
p := &x
Declare a variable, take its address with &, use the pointer. This is the form you reach for most often, because most pointers in real code aim at existing variables: a local, a field inside something else, a slice element.
Way 2: new(T) allocates a fresh zero-valued T
new(T) is a built-in function that allocates a new, zero-valued value of type T and returns a pointer to it:
p := new(int)
fmt.Println(*p) // 0 (zero value of int)
*p = 42
fmt.Println(*p) // 42
new(int) is equivalent to var tmp int; p := &tmp, but without the intermediate name. The Go runtime allocates the storage and hands you the pointer in one step.
In practice, you will see new(T) rarely. For primitives, it is hardly ever shorter than just declaring a variable. Its real niche is when you need a pointer to a zero-valued value passed straight into another call, with no binding in between.
Way 3: &T{...} for structs
The third form is the composite literal address, which takes over as the common case once structs arrive in the next chapter:
// You will see this a lot, starting next chapter:
p := &Point{X: 1, Y: 2}
&Point{...} builds a Point with the given field values and returns a pointer to it, all in one step. This is the idiomatic way to allocate a struct in Go. new(Point) would work too, but it gives you a pointer to a zero-valued Point with no fields set, which is rarely what you want.
Why &T{...} wins over new(T) for structs
Two reasons to prefer the composite-literal form once structs arrive:
- You can set fields at the same time.
&Point{X: 1, Y: 2}tells the reader what the pointer refers to.new(Point)hands you a blank Point and leaves you to fill it in on subsequent lines, which is more code and more places for a mistake. - It matches other Go syntax. Slices use
[]int{1, 2, 3}, maps usemap[string]int{"a": 1}, and structs extend the same pattern:&Point{...}just says "build one and give me the address".
new exists for completeness and for the occasional case where its shorter syntax genuinely helps. You can write real Go code for a long time without typing new once.
- Pointer to a variable you already have:
p := &x. Most common. - Pointer to a freshly constructed struct:
p := &Point{...}. The next chapter's main pattern. - Pointer to a zero-valued anything, with no intermediate name:
p := new(T). Rarely needed; reach for it when neither of the above fits.
When you feel the urge to type new, pause and ask whether a plain variable or a composite literal would read better. Usually one of them does.
Starter is almost empty. In main:
- Allocate a pointer to a zero-valued int with
new(int), bound top. - Write
99through the pointer with*p = 99. - Print
*pon its own line (should be99). - Print
p == nilon its own line (should befalse, becausenewnever returnsnil).
Expected output:
99
false
99 false