Go 为什么errorString是结构而不是字符串
我正在阅读Go编程语言书,书中描述了错误包和接口Go 为什么errorString是结构而不是字符串,go,Go,我正在阅读Go编程语言书,书中描述了错误包和接口 package errors type error interface { Error() string } func New(text string) error { return &errorString{text} } type errorString struct { text string } func (e *errorString) Error() string { return e.text } 上面说
package errors
type error interface {
Error() string
}
func New(text string) error { return &errorString{text} }
type errorString struct { text string }
func (e *errorString) Error() string { return e.text }
上面说
errorString的基本类型是一个结构,而不是一个字符串,用于保护其表示形式不受意外(或预谋)更新的影响
这是什么意思?由于未导出errorString
,包不会隐藏底层类型吗
更新
下面是我用来实现errorString
的测试代码,它使用string
。请注意,当您尝试从另一个包中使用它时,不能仅将字符串指定为错误
package testerr
type Error interface {
Error() string
}
func New(text string) Error {
return errorString(text)
}
type errorString string
func (e errorString) Error() string { return string(e) }
并用建议的代码对其进行测试
func main() {
err := errors.New("foo")
err = "bar"
fmt.Prinln(err)
}
将在编译时产生错误
无法将“bar”(类型字符串)用作类型测试仪。分配错误:
字符串未实现testerr.Error(缺少错误方法)
当然,这有一个不利的方面,因为碰巧有相同错误字符串的不同错误将被评估为相等,这是我们不希望看到的。这本书关于“保护表示免受无意更新”的解释对我来说似乎有误导性。无论
errorString
是结构还是字符串,错误消息仍然是字符串,并且字符串是
这也不是关于独特性的争论。例如,errors.New(“EOF”)==io.EOF
的计算结果为false
,尽管这两个错误具有完全相同的底层消息。即使errorString
是一个字符串,只要errors,同样适用。New
将返回指向它的指针(.)
您可以说实现错误的结构是惯用的,因为这也是标准库引入自定义错误的方式。查看encoding/json
包中的SyntaxError
:
type SyntaxError struct {
Offset int64 // error occurred after reading Offset bytes
// contains filtered or unexported fields
}
func (e *SyntaxError) Error() string { return e.msg }
()
此外,实现error
接口的结构没有性能影响,也不会比字符串实现消耗更多内存。请参阅。您的testerr软件包工作得很好,但它失去了“基于结构的”标准错误软件包的一个主要功能:不相等:
package main
import ( "fmt"; "testerr"; "errors" )
func main() {
a := testerr.New("foo")
b := testerr.New("foo")
fmt.Println(a == b) // true
c := errors.New("foo")
d := errors.New("foo")
fmt.Println(c == d) // false
}
当errorString
为普通字符串时,具有相同字符串内容的不同错误将相等。原始代码使用指向struct的指针,每个New
分配一个新的struct,因此与=
相比,从New
返回的不同值是不同的,尽管错误文本相同
此处不允许任何编译器生成相同的指针。“不同的调用产生不同的错误值”这一特性对于防止意外的错误相等非常重要。您的testerr可以通过使用*errorString
实现Error
来修改以产生此属性。试试看:你需要一个临时地址。它“感觉”不对。我们可以想象一个奇特的编译器,它将字符串值内部化,并可能返回相同的指针(因为它指向相同的内部化字符串),这将打破这个很好的不等式属性 @shebaw我明白了。我将错误
接口排除在等式之外。我修改了我的答案。我想这本书给出的第二个解释是,如果我们把errorString
作为一个字符串,那么任何碰巧有相同错误字符串的错误都将计算为True
。例如:io.EOF==errors.New(“EOF”)
这是不正确的。@没错,这也是不正确的。如果errors.New
返回指向errorString
的指针,则无论errorString
是结构还是字符串都无关紧要。