pointers - golang 和指针接收器中的自定义错误
问题描述
通过网络和stackoverflow阅读有关值接收器与指针接收器的信息,我理解基本规则是:如果您不打算修改接收器,并且接收器相对较小,则不需要指针。
然后,阅读有关实现error
接口的信息(例如https://blog.golang.org/error-handling-and-go),我看到该Error()
函数的示例都使用指针接收器。
然而,我们并没有修改接收器,而且结构非常小。
return &appError{}
我觉得没有指针( vs )的代码要好得多return appError{}
。
这些示例使用指针是否有原因?
解决方案
首先,您链接并从中获取示例的博客文章appError
不是. 它是一个包含错误值和示例实现所使用的其他相关信息的包装器,它们没有被公开,也没有被用作值。error
appError
*appError
error
因此,您引用的示例与您的实际问题无关。但是要回答标题中的问题:
一般来说,一致性可能是原因。如果一个类型有很多方法并且有些需要指针接收器(例如,因为它们修改了值),通常用指针接收器声明所有方法很有用,这样就不会混淆类型和指针类型的方法集。
关于实现的回答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()
保证(因为它返回指向未导出结构值的指针)。
推荐阅读
- c - GCC:优化内存加载和存储
- python - 在哪里放置 break 语句或如何更改我的代码?
- apache-spark - 如何在 Arch 中使用 Apache Spark?
- python-3.x - Python 日志记录将处理程序设置为不同级别
- javascript - Codepen,Javascript,如何将keyCode上下添加到paddle
- excel - 使用循环根据两个条件定位行并将当前时间插入第 12 列
- python - python如何让timeit识别定义的输入
- python - python中读取网页的方法及区别
- docker - 将 windows 目录共享到 Linux docker 容器
- python - 计算平均分数并返回一个字符串