面试题答案
一键面试返回错误而非抛出异常的策略
- 业务逻辑校验场景:
- 在处理用户输入、参数校验等业务逻辑时,应返回错误。例如,一个接收用户注册信息的函数,若用户名长度不符合要求,函数应返回相应错误,而不是抛出异常。
- 示例代码:
func RegisterUser(username string, password string) error {
if len(username) < 3 {
return fmt.Errorf("用户名长度至少为3位")
}
// 其他注册逻辑
return nil
}
- 外部资源操作场景:
- 当与数据库、文件系统、网络服务等外部资源交互时,返回错误。比如连接数据库失败、读取文件不存在等情况。
- 示例代码:
func ReadFileContent(filePath string) (string, error) {
data, err := ioutil.ReadFile(filePath)
if err!= nil {
return "", fmt.Errorf("读取文件 %s 失败: %w", filePath, err)
}
return string(data), nil
}
- 流程控制场景:
- 在业务流程中有条件判断需要中断流程时,返回错误。例如,一个订单处理流程,若库存不足则无法完成订单,此时应返回错误。
- 示例代码:
func ProcessOrder(order Order, stock int) error {
if order.Quantity > stock {
return fmt.Errorf("库存不足,无法处理订单")
}
// 处理订单逻辑
return nil
}
使用异常的合理情况
- 不可恢复的运行时错误:
- 当遇到如内存溢出、栈溢出等不可恢复的错误时,使用异常(在Go语言中通过
panic
)。这些情况通常表示程序处于严重错误状态,无法继续正常运行。 - 示例代码:
- 当遇到如内存溢出、栈溢出等不可恢复的错误时,使用异常(在Go语言中通过
func allocateHugeMemory() {
data := make([]int, 1<<30) // 尝试分配超大内存,可能导致内存溢出
// 其他逻辑
}
- 程序内部逻辑错误:
- 当检测到代码中存在逻辑错误,如违反了程序的不变性条件。例如,在一个只允许单例的对象创建逻辑中,检测到已经存在实例还尝试创建新实例,可使用
panic
。 - 示例代码:
- 当检测到代码中存在逻辑错误,如违反了程序的不变性条件。例如,在一个只允许单例的对象创建逻辑中,检测到已经存在实例还尝试创建新实例,可使用
var singletonInstance *Singleton
func GetSingletonInstance() *Singleton {
if singletonInstance!= nil {
panic("已经存在单例实例,不能重复创建")
}
singletonInstance = &Singleton{}
return singletonInstance
}
代码中实现权衡确保稳定性和可维护性
- 错误处理:
- 使用
if err!= nil
语句对返回的错误进行检查和处理。可以采用链式错误处理,将底层错误包装并返回,方便上层调用者定位问题。 - 示例代码:
- 使用
func main() {
err := RegisterUser("ab", "password")
if err!= nil {
log.Println("注册用户失败:", err)
}
}
- 异常处理:
- 使用
recover
函数来捕获panic
,并进行适当的处理,如记录日志、清理资源等。一般在主函数或启动服务的入口处进行recover
处理,防止程序崩溃。 - 示例代码:
- 使用
func main() {
defer func() {
if r := recover(); r!= nil {
log.Println("捕获到异常:", r)
}
}()
allocateHugeMemory()
}
通过合理地返回错误和使用异常,以及规范的错误和异常处理机制,可以确保Go语言微服务项目的稳定性和可维护性。在业务场景中优先使用返回错误来处理可预期的问题,而在不可恢复或程序逻辑错误时谨慎使用异常,并做好异常捕获和处理。