从函数和调用者到终端的Golang错误处理

时间:2018-09-28 19:49:01

标签: go error-handling

我想问一下错误处理的最佳实践, 假设我有以下读取文件的函数来解析它, 当找不到文件且解组失败时,可能会返回两种类型的错误

func Parse(source string) (bma.Bma, error) {
    file, err := ioutil.ReadFile(source + "bma.yaml")
    m := bma.Bma{}
    if err != nil {
        logs.Error("Not able to read the bma file")
        return m, err
    }
    err = yaml.Unmarshal([]byte(file), &m)
    if err != nil {
        logs.Error("Not able to unmarshal the bma file ")
        return m, err
    }
    return m, err
}

现在,如果我调用此函数并且出现错误,我也打印了此错误,则该程序是CLI程序,因此我认为如果出现问题,可以吗,或者有更好的方法,将会打印太多错误?

bma ,err := Parse("path")
    if err != nil {
        logs.Error("Error while parsing ")
        return m, err
    }

2 个答案:

答案 0 :(得分:1)

我认为您要问的是更多关于何时打印错误而不是何时处理错误。就我而言,我喜欢打印所有日志,如果我认为它们将来对我有用的话。

对于您而言,消息logs.Error("Error while parsing ")太冗长了,因为您在那里没有显示任何详细信息。

您可以考虑的其他方法是将自定义错误返回到顶层函数,而不是在更深层的函数中,仅在其中显示日志消息。在这个例子中,应该是这样的:

func main() {
    bma, err := Parse("path")
    if err != nil {
        log.Println(err)
        return
    }
}

func Parse(source string) (bma.Bma, error) {
    file, err := ioutil.ReadFile(source + "bma.yaml")
    m := bma.Bma{}
    if err != nil {
        return m, fmt.Errorf("Not able to read the bma file: %s", err.Error())
    }
    err = yaml.Unmarshal([]byte(file), &m)
    if err != nil {
        return m, fmt.Errorf("Not able to unmarshal the bma file: %s", err.Error())
    }
    return m, err
}

答案 1 :(得分:0)

package main

import (
    "fmt"
    "log"
    "os"
)

func main() {
    fileName := "main.go"
    err := parse(fileName)
    if err != nil {
        log.Println(err)
    }
    log.Println(parse2(fileName))
    log.Println(parse3(fileName))
    //Incase of library one need to create new errors and export them
    //see error.go file of some stdlib packages for some example
}

func parse(s string) error {
    _, err := os.Open(s + "t") // fails
    if err != nil {
        // no need to add any custom err information,
        // as err contains required details (action, fileName, error)
        return err
    }
    return nil
}

func parse2(s string) error {
    // Incase you must handle errors
    _, err := os.Open(s + "t") // fails
    if err != nil {

        err = (err.(*os.PathError)).Err //only, if you must handle it

        if err == os.ErrPermission {
            //send notification to developer, about user
        } else if err == os.ErrNotExist {
            //user is so irresponsible, block him
        } else if os.IsNotExist(err) {
            fmt.Println("found the cause")
        }
        return err

    }
    return nil
}

func parse3(s string) error {
    err := badError(s)
    if err != nil {
        // wrap error with required context information,
        // if err doesn't return proper error
        // or if you have more useful information
        return fmt.Errorf("%s ,%s", s, err)
    }
    return nil
}

func badError(s string) error {
    return fmt.Errorf("badError,I'm not saying why it failed, and what's the argument which caused me to fail, and making error without actually any content")
}