首页 > 解决方案 > golang 和指针接收器中的自定义错误

问题描述

通过网络和stackoverflow阅读有关值接收器与指针接收器的信息,我理解基本规则是:如果您不打算修改接收器,并且接收器相对较小,则不需要指针。

然后,阅读有关实现error接口的信息(例如https://blog.golang.org/error-handling-and-go),我看到该Error()函数的示例都使用指针接收器。

然而,我们并没有修改接收器,而且结构非常小。

return &appError{}我觉得没有指针( vs )的代码要好得多return appError{}

这些示例使用指针是否有原因?

标签: pointersgoerror-handlingpass-by-reference

解决方案


首先,您链接并从中获取示例的博客文章appError不是. 它是一个包含错误值和示例实现所使用的其他相关信息的包装器,它们没有被公开,也没有被用作值。errorappError*appErrorerror

因此,您引用的示例与您的实际问题无关。但是要回答标题中的问题:

一般来说,一致性可能是原因。如果一个类型有很多方法并且有些需要指针接收器(例如,因为它们修改了值),通常用指针接收器声明所有方法很有用,这样就不会混淆类型和指针类型的方法集

关于实现的回答error:当你使用一个struct值来实现一个error值时,使用非指针来实现error接口是很危险的。为什么会这样?

因为error是接口。和接口值相媲美。并且通过比较它们包装的值来比较它们。并且您会根据其中包含的值/类型得到不同的比较结果!因为如果您在其中存储指针,则如果它们存储相同的指针,则错误值将相等。并且如果您在其中存储非指针(结构),则如果结构值相等,则它们是相等的。

要详细说明这一点并显示一个示例:

标准库有一个errors包。string您可以使用该errors.New()函数从值创建错误值。如果你看一下它的实现(errors/errors.go),很简单:

// Package errors implements functions to manipulate errors.
package errors

// New returns an error that formats as the given text.
func New(text string) error {
    return &errorString{text}
}

// errorString is a trivial implementation of error.
type errorString struct {
    s string
}

func (e *errorString) Error() string {
    return e.s
}

该实现返回一个指向一个非常简单的结构值的指针。这样,如果您创建 2 个具有相同string值的错误值,它们将不相等:

e1 := errors.New("hey")
e2 := errors.New("hey")
fmt.Println(e1, e2, e1 == e2)

输出:

hey hey false

这是故意的。

现在,如果您要返回一个非指针:

func New(text string) error {
    return errorString{text}
}

type errorString struct {
    s string
}

func (e errorString) Error() string {
    return e.s
}

2个相同的错误值string将相等:

e1 = New("hey")
e2 = New("hey")
fmt.Println(e1, e2, e1 == e2)

输出:

hey hey true

试试Go Playground上的示例。

一个重要的例子:查看存储在变量中的错误值io.EOF

var EOF = errors.New("EOF")

预计io.Reader实现会将此特定错误值返回到输入结束的信号。因此,您可以平静地比较 to 返回的错误,Reader.Read()io.EOF判断是否达到输入结束。您可以确定,如果它们偶尔返回自定义错误,它们将永远不会等于io.EOF,这就是errors.New()保证(因为它返回指向未导出结构值的指针)。


推荐阅读