Sundrique
Sundrique

Reputation: 637

How to assign to a field of nil struct in golang

I'm trying to assign a value to a field, but my program panics with runtime error: invalid memory address or nil pointer dereference.

package main

type Node struct {
    Value int
}

func (n *Node) SetValue(value int) {
    n.Value = value
}

func main() {
    var n *Node

    n.SetValue(1)
}

This is reasonable since variable is nil.
But I've fount some Go internal structs are allowed to do this, e.g. bytes.Buffer

package main

import "bytes"
import "io"
import "os"

func main() {
    var b bytes.Buffer
    b.Write([]byte("Hello world"))
    io.Copy(os.Stdout, &b)
}

Here is the `bytes.Buffer source code

func (b *Buffer) Write(p []byte) (n int, err error) {
    b.lastRead = opInvalid
    m := b.grow(len(p))
    return copy(b.buf[m:], p), nil
}

Is it the thing only builtin structs can do or it's possible to accomplish this in my code?

EDIT
Here is the working example. Thanks @twotwotwo for suggestion.

package main

import "fmt"

type Node struct {
    Value int
}

func (n *Node) SetValue(value int) {
    n.Value = value
}

func main() {
    var n Node

    n.SetValue(1)

    fmt.Println(n.Value)
}

Upvotes: 0

Views: 6354

Answers (1)

twotwotwo
twotwotwo

Reputation: 30057

The crucial thing is var b bytes.Buffer doesn't get you a nil pointer, it gets you a bytes.Buffer object with all its fields initialized with their zero values (in machine terms, with zero bytes). The spec says the zero value is "false for booleans, 0 for integers, 0.0 for floats, "" for strings, and nil for pointers, functions, interfaces, slices, channels, and maps"; follow that link for more detail.

It is possible to make your own structs whose zero values work and the Go team encourages it. struct Position { x, y int } is an easy example and Effective Go gives a more realistic one. But note that that doesn't make the nil pointer work; you would still need new(Node) or var n Node to allocate the zero Node. Same for bytes.Buffer.

Another common use of zero values: wherever your users create structs of your type directly (as folks do with, say, http.Server), the zero value is the default for any fields they don't specify. It's the default in a lot of other places: what you get for a not-found map key, if you receive from a closed channel, and probably others.

Upvotes: 7

Related Questions