我正在阅读The Go Programming Language一书及其对错误包和界面的描述
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) }
编译时最终会产生错误
cannot use "bar" (type string) as type testerr.Error in assignment:
string does not implement testerr.Error (missing Error method)
当然,这有一个缺点,因为碰巧具有相同错误字符串的不同错误将评估为我们不想要的相等.
该书关于"保护代表免受无意更新"的解释对我来说似乎有误导性.无论errorString
是结构还是字符串,错误消息仍然是一个字符串,字符串是不可变的规范.
这也不是关于独特性的争论.例如,errors.New("EOF") == io.EOF
求值为false
,尽管两个错误都具有完全相同的基础消息.即使errorString
是一个字符串也是如此,只要errors.New
返回一个指向它的指针(参见我的例子).
你可以说结构实现error
是惯用的,因为这也是标准库引入自定义错误的方式.SyntaxError
从encoding/json
包中看一下:
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
接口的结构没有性能影响,并且不会在字符串实现上消耗更多内存.请参阅转到数据结构.