为了账号安全,请及时绑定邮箱和手机立即绑定

为什么 errorString 是一个结构体,而不是一个字符串

为什么 errorString 是一个结构体,而不是一个字符串

Go
桃花长相依 2021-11-29 16:38:08
我正在阅读 The Go Programming Language 一书,并在其中描述了错误包和接口package errorstype 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使用 a实现的测试代码string。请注意,当尝试从另一个包中使用它时,您不能仅将字符串分配为错误。package testerrtype Error interface {        Error() string}func New(text string) Error {        return errorString(text)}type errorString stringfunc (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)当然,这有一个缺点,因为碰巧具有相同错误字符串的不同错误将评估为相等,这是我们不想要的。
查看完整描述

2 回答

?
MM们

TA贡献1886条经验 获得超2个赞

这本书关于“保护表示免受无意更新”的解释对我来说似乎具有误导性。无论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接口的结构没有性能影响,并且不会比字符串实现消耗更多内存。请参阅Go 数据结构。


查看完整回答
反对 回复 2021-11-29
?
Qyouu

TA贡献1786条经验 获得超11个赞

您的 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如果与==相同的错误文本进行比较,则返回的不同值是不同的。


不允许编译器在此处生成相同的指针。而“对 New 的不同调用会产生不同的错误值”这一特性对于防止意外的错误相等很重要。您可以通过*errorString执行来修改您的测试器以产生此属性Error。试试看:你需要一个临时取的地址。“感觉”不对。可以想象一个花哨的编译器,它内部化字符串值并可能返回相同的指针(因为它指向相同的内部化字符串),这会破坏这个很好的不等式属性。


查看完整回答
反对 回复 2021-11-29
  • 2 回答
  • 0 关注
  • 312 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信