面试题答案
一键面试自定义error类型的设计原则
- 语义清晰:自定义error类型的错误信息应能准确传达错误发生的原因。例如,在一个用户注册模块中,若用户名已存在,可以定义如下error:
type UsernameExistsError struct {
Username string
}
func (u UsernameExistsError) Error() string {
return fmt.Sprintf("username %s already exists", u.Username)
}
- 简洁性:error类型的结构和方法应简洁,避免过度复杂。例如,对于文件读取错误,只需要包含文件名等关键信息:
type FileReadError struct {
Filename string
}
func (f FileReadError) Error() string {
return fmt.Sprintf("failed to read file %s", f.Filename)
}
- 分层设计:按照业务逻辑的层次划分error类型。比如在电商系统中,将商品模块、订单模块的error分开定义,方便管理和定位问题。
确保不同模块间error的兼容性和可扩展性
- 接口约定:定义一个通用的error接口,不同模块的自定义error都实现该接口。例如:
type BusinessError interface {
Error() string
ErrorCode() int
}
各个模块的error实现该接口:
type ProductNotFoundError struct {
ProductID string
}
func (p ProductNotFoundError) Error() string {
return fmt.Sprintf("product %s not found", p.ProductID)
}
func (p ProductNotFoundError) ErrorCode() int {
return 1001
}
- 版本控制:在分布式系统中,不同模块可能有不同的版本。通过在error信息中包含版本号等信息,确保不同版本模块间的兼容性。例如,在error结构体中添加Version字段:
type PaymentError struct {
Version int
ErrorMsg string
}
func (p PaymentError) Error() string {
return fmt.Sprintf("version %d: %s", p.Version, p.ErrorMsg)
}
- 错误码规范:制定统一的错误码规范,不同模块使用不同范围的错误码。比如商品模块错误码范围是1000 - 1999,订单模块是2000 - 2999。
基于自定义error类型实现有效的错误追踪和定位
- 上下文信息:在error结构体中添加上下文信息,方便定位错误发生的具体位置。例如,在数据库操作error中,记录执行的SQL语句:
type DatabaseError struct {
SQLStmt string
ErrorMsg string
}
func (d DatabaseError) Error() string {
return fmt.Sprintf("SQL: %s, error: %s", d.SQLStmt, d.ErrorMsg)
}
- 日志记录:在捕获error时,记录详细的日志,包括调用栈信息。例如使用
logrus
库:
func main() {
err := someFunction()
if err != nil {
logrus.WithError(err).Error("An error occurred")
}
}
- 错误链:在分布式系统中,可能一个错误由多个子错误组成。可以通过实现
Unwrap
方法来构建错误链。例如:
type OuterError struct {
ErrMsg string
InnerError error
}
func (o OuterError) Error() string {
return fmt.Sprintf("outer error: %s, inner error: %v", o.ErrMsg, o.InnerError)
}
func (o OuterError) Unwrap() error {
return o.InnerError
}
假设案例场景:一个电商系统,用户下单时,需要调用商品模块检查商品库存,调用支付模块进行支付。如果商品库存不足,商品模块返回InsufficientStockError
,支付模块在调用时捕获该错误并包装成OrderFailedError
返回给上层业务逻辑。通过上述设计原则和方法,可以确保错误在不同模块间的有效传递、追踪和定位。