golang学习笔记——错误处理

错误与panic

Go 具有 panicrecover 之类的内置函数来管理程序中的异常或意外行为。 但错误是已知的失败,你的程序应该可以处理它们。

错误处理

使用以下代码片段来练习各种错误处理策略

package main

import (
    "fmt"
    "os"
)

type Employee struct {
    ID        int
    FirstName string
    LastName  string
    Address   string
}

func main() {
    employee, err := getInformation(1001)
    if err != nil {
        // Something is wrong. Do something.
    } else {
        fmt.Print(employee)
    }
}

func getInformation(id int) (*Employee, error) {
    employee, err := apiCallEmployee(1000)
    return employee, err
}

func apiCallEmployee(id int) (*Employee, error) {
    employee := Employee{LastName: "Doe", FirstName: "John"}
    return &employee, nil
}

我们将重点介绍如何修改 getInformationapiCallEmployeemain 函数,以展示如何处理错误。

错误处理策略

直接返回错误给调用者

将错误返回给调用方,而不执行其他任何操作

func getInformation(id int) (*Employee, error) {
    employee, err := apiCallEmployee(1000)
    if err != nil {
        return nil, err // Simply return the error to the caller.
    }
    return employee, nil
}

返回错误给调用者,但添加更多信息

使用 fmt.Errorf() 函数,向错误添加更多上下文,但仍返回原始错误

func getInformation(id int) (*Employee, error) {
    employee, err := apiCallEmployee(1000)
    if err != nil {
        return nil, fmt.Errorf("Got an error when getting the employee information: %v", err)
    }
    return employee, nil
}

暂时性错误进行重试逻辑

使用重试策略调用函数三次并等待两秒钟

func getInformation(id int) (*Employee, error) {
    for tries := 0; tries < 3; tries++ {
        employee, err := apiCallEmployee(1000)
        if err == nil {
            return employee, nil
        }

        fmt.Println("Server is not responding, retrying ...")
        time.Sleep(time.Second * 2)
    }

    return nil, fmt.Errorf("server has failed to respond to get the employee information")
}

创建可重用的错误

使用 errors.New() 函数创建错误并重复使用

var ErrNotFound = errors.New("Employee not found!")

func getInformation(id int) (*Employee, error) {
    if id != 1001 {
        return nil, ErrNotFound
    }

    employee := Employee{LastName: "Doe", FirstName: "John"}
    return &employee, nil
}

判断错误类型

使用errors.Is() 函数允许你比较获得的错误的类型

employee, err := getInformation(1000)
if errors.Is(err, ErrNotFound) {
    fmt.Printf("NOT FOUND: %v\n", err)
} else {
    fmt.Print(employee)
}

错误处理的推荐做法

在 Go 中处理错误时,请记住下面一些推荐做法:

  • 始终检查是否存在错误,即使预期不存在。 然后正确处理它们,以免向最终用户公开不必要的信息。
  • 在错误消息中包含一个前缀,以便了解错误的来源。 例如,可以包含包和函数的名称。
  • 创建尽可能多的可重用错误变量。
  • 了解使用返回错误和 panic 之间的差异。 不能执行其他操作时再使用 panic。 例如,如果某个依赖项未准备就绪,则程序运行无意义(除非你想要运行默认行为)。
  • 在记录错误时记录尽可能多的详细信息(我们将在下一部分介绍记录方法),并打印出最终用户能够理解的错误。

面试题

以下是5道关于Go语言错误处理的面试题:

Go语言中如何处理错误?
解释Go语言中的panic和recover机制。
如何在Go语言中实现自定义错误类型?
Go语言中的错误处理与异常处理有什么区别?
在Go语言中,如何处理函数返回的错误?

这些题目涵盖了Go语言中错误处理的基本概念、自定义错误类型、异常处理以及函数返回错误的处理方式等方面。通过回答这些问题,可以考察面试者对Go语言错误处理机制的理解和掌握程度。

1.Go语言中如何处理错误

在Go语言中,错误处理是一种重要的编程范式,通过使用错误值和错误类型来处理程序中可能出现的异常情况。以下是在Go语言中处理错误的常见方法:

  1. 返回错误值:函数可以返回一个错误值作为函数结果的一部分,调用者可以使用这个错误值来判断函数执行是否成功。错误值通常是一个空接口类型(interface{})或者具体的错误类型。

    func divide(a, b int) (int, error) {
        if b == 0 {
            return 0, errors.New("division by zero")
        }
        return a / b, nil
    }
    

    在上面的例子中,divide函数返回两个值:商和错误。如果除数为零,则返回一个非空的错误值。

  2. 检查错误:调用者需要检查函数返回的错误值,并根据错误类型采取相应的处理措施。可以使用if语句和==操作符来检查错误是否为nil

    result, err := divide(10, 0)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    fmt.Println("Result:", result)
    

    在上面的例子中,如果divide函数返回的错误不为nil,则打印错误信息并提前返回。

  3. 错误类型:Go语言提供了内置的error类型,用于表示错误信息。开发者也可以定义自己的错误类型,以便更好地描述错误的性质和原因。

    type MyError struct {
        Message string
    }
    
    func (e *MyError) Error() string {
        return e.Message
    }
    

    在上面的例子中,定义了一个自定义的错误类型MyError,它有一个字符串类型的字段Message和一个实现了Error()方法的方法。通过实现Error()方法,可以将自定义错误类型转换为字符串。

  4. 延迟处理:有时我们希望延迟错误处理,将错误传递给上层调用者或者进行其他处理。在这种情况下,可以使用空接口类型(interface{})来传递错误值。

    func doSomething() (interface{}, error) {
        // ...执行一些操作...
        return result, nil // 返回结果和空错误值
    }
    

    在上面的例子中,函数doSomething返回一个空接口类型和一个错误值。调用者可以根据需要检查这个错误值。如果调用者不需要关心错误信息,可以将其忽略。

  5. 恢复和传播错误:当程序出现未处理的异常情况时,可以使用panic函数触发程序中断。在函数中可以使用recover函数来捕获并处理panic。同时,Go语言的运行时系统会传播错误到调用堆栈的上一层,直到找到处理错误的代码或程序被中断。

这些是在Go语言中处理错误的常见方法。通过合理地使用这些方法,可以有效地处理程序中的异常情况,提高代码的健壮性和可靠性。

2.解释Go语言中的panic和recover机制

Go语言中的panic和recover机制是用于错误处理和异常处理的机制。

Panic

Panic是一种会立即停止程序执行的机制。当程序遇到严重错误或无法恢复的错误时,可以使用panic函数触发panic。一旦panic被触发,程序将立即停止执行当前函数的剩余代码,并向上层调用栈传播panic。如果上层调用者没有使用recover捕获panic,程序将终止。

Panic通常用于处理严重错误或无法恢复的错误,例如内存不足、文件找不到等。

Recover

Recover是一种用于捕获和处理panic的机制。它只能在defer函数或匿名函数中被调用,并且只能捕获当前函数调用栈中的panic。如果在defer函数中调用了recover函数,它会捕获到当前函数调用栈中的panic,并返回该panic的值。然后,defer函数可以对该值进行处理,例如记录日志、返回错误等。

Recover通常用于处理可以恢复的错误或异常情况,例如用户输入验证失败、数据库连接失败等。通过使用recover,可以将错误处理逻辑与正常的程序逻辑分离,提高代码的可读性和可维护性。

func doSomething() {
    panic("Something went wrong!")
}

func main() {
    defer func() {
        if err := recover(); err != nil {
            fmt.Println("Recovered:", err)
        }
    }()
    doSomething()
    fmt.Println("This line will not be executed")
}

在main函数中,使用defer和recover来捕获并处理panic。通过recover函数,可以恢复程序的控制流程,并打印错误消息。

总结

Panic用于触发程序中断,而Recover用于捕获和处理panic。合理地使用panic和recover机制可以帮助我们更好地处理错误和异常情况,提高程序的健壮性和可靠性。在Go语言中,建议对于严重错误或无法恢复的错误使用panic,而对于可以恢复的错误或异常情况使用Recover。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值