Golang中如何将error类型断言为自定义错误类型
是的,现在想想就很明显了。ErrB 确实是一个新的接口类型,但它是一个与 error 具有相同布局的 interface 类型。我同样可以像这样定义 ErrB,类型断言也能正常工作。
更多关于Golang中如何将error类型断言为自定义错误类型的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Go语言中,error是一个接口类型
https://golang.org/ref/spec#Errors
当你对接口类型进行类型断言时,它只是检查是否满足给定的接口。也就是说(在你给出的示例中),检查errA是否满足errB接口。errA的值不会改变,但结果表达式是errB类型,并具有errB的方法。在这种情况下,errA和errB都是error的别名,所以类型断言实际上没有改变任何东西。你只是成功地将errA类型的东西转换成了errB类型。
你的Println()语句打印的是两个具有相同值的东西,所以它们打印的内容是相同的。
在Go语言中,当使用错误值(而非错误类型)进行类型断言时,如果错误值实现了目标接口,断言就会成功。在你的第一个示例中,ErrA 和 ErrB 都实现了 error 接口,并且它们都是通过相同的底层字符串类型实现的。由于类型断言检查的是值是否满足接口,而不是具体的类型,因此即使 errA 是 ErrA 类型,它也能被断言为 ErrB,因为两者底层都是字符串,且 ErrB 的方法集是 error 接口的子集。
以下是示例代码说明问题:
package main
import "fmt"
type ErrA string
func (e ErrA) Error() string {
return string(e)
}
type ErrB string
func (e ErrB) Error() string {
return string(e)
}
func main() {
var errA error = ErrA("error A")
// 类型断言为 ErrB 会成功,因为 errA 的底层值满足 ErrB 的接口
if errB, ok := errA.(ErrB); ok {
fmt.Printf("Assertion to ErrB succeeded: %v\n", errB)
} else {
fmt.Println("Assertion to ErrB failed")
}
}
输出会是:
Assertion to ErrB succeeded: error A
这是因为 errA 的底层值是一个字符串,而 ErrB 也只需要一个字符串来实现 Error() string 方法。类型断言在这里检查的是值的行为,而不是具体类型。
为了解决这个问题,推荐使用结构体来封装错误,这样可以包含额外的类型信息。例如:
package main
import "fmt"
type ErrA struct {
msg string
}
func (e ErrA) Error() string {
return e.msg
}
type ErrB struct {
msg string
}
func (e ErrB) Error() string {
return e.msg
}
func main() {
var errA error = ErrA{msg: "error A"}
// 类型断言为 ErrB 会失败,因为底层类型不同
if errB, ok := errA.(ErrB); ok {
fmt.Printf("Assertion to ErrB succeeded: %v\n", errB)
} else {
fmt.Println("Assertion to ErrB failed")
}
}
输出:
Assertion to ErrB failed
使用结构体是更可靠的方法,因为它确保了类型的唯一性。如果不想使用结构体,可以考虑在错误类型中添加一个未导出的方法,以在类型断言时区分它们,但这通常比结构体更复杂。结构体方法是最直接和清晰的解决方案。


