Go 为什么errorString是结构而不是字符串

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 } 上面说

我正在阅读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 }
上面说

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
是结构还是字符串都无关紧要。