如何在Go语言中将值分配给nil结构体的字段

huangapple go评论81阅读模式
英文:

How to assign to a field of nil struct in golang

问题

我正在尝试为一个字段赋值,但是我的程序出现了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)
}

这是合理的,因为变量是nil。但是我发现一些Go内部结构允许这样做,例如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)
}

这是bytes.Buffer的源代码:

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
}

这只是内置结构才能做到的吗?还是我的代码也可以实现这个功能?

编辑
这是一个可工作的示例。感谢@twotwotwo的建议。

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)
}
英文:

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.<br/>
But I've fount some Go internal structs are allowed to do this, e.g. bytes.Buffer

package main

import &quot;bytes&quot;
import &quot;io&quot;
import &quot;os&quot;

func main() {
    var b bytes.Buffer
    b.Write([]byte(&quot;Hello world&quot;))
    io.Copy(os.Stdout, &amp;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<br/>
Here is the working example. Thanks @twotwotwo for suggestion.

package main

import &quot;fmt&quot;

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)
}

答案1

得分: 7

关键的是var b bytes.Buffer不会得到一个nil指针,而是得到一个bytes.Buffer对象,其中所有字段都被初始化为它们的零值(在机器术语中,即零字节)。规范说明零值为“布尔值为false,整数为0,浮点数为0.0,字符串为空字符串,指针、函数、接口、切片、通道和映射为nil”;请点击链接获取更多详细信息。

你可以创建自己的结构体,使其零值起作用,Go团队鼓励这样做struct Position { x, y int }是一个简单的例子,Effective Go提供了一个更实际的例子。但请注意,这并不意味着nil指针可以工作;你仍然需要使用new(Node)var n Node来分配零值的Node。对于bytes.Buffer也是一样。

零值的另一个常见用途是:无论何时用户直接创建您的类型的结构体(就像人们使用http.Server一样),零值都是他们未指定字段的默认值。在许多其他地方也是默认值:当你在映射中找不到键时,从关闭的通道接收数据时,以及可能还有其他情况。

英文:

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.

huangapple
  • 本文由 发表于 2015年3月22日 14:34:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/29191689.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定