Как аккуратно отложить выполнение функции, которая может вернуть ошибку? - PullRequest
0 голосов
/ 26 ноября 2018

Большинство функций очистки, особенно связанных с операциями ввода-вывода, возвращают error, и обычно мы предпочитаем defer их выполнение в случае, если мы не забудем вызвать их, когда закончим сприобретенные ресурсы.Например, в какой-то момент кода мы могли бы написать что-то вроде этого:

var r *SomeResource
var err error
if r, err = Open(/* parameters */); err != nil {
    return nil, err
}
defer r.Close() // This might return an error

Кажется, что если функция Close возвращает ошибку, она будет проигнорирована.Как мы можем аккуратно обработать возвращенную error от такой функции?

Ответы [ 3 ]

0 голосов
/ 26 ноября 2018

Мы можем справиться с этим следующими способами:

way-1:

func myFn() error {
    var err error
    if r, err = Open(/* parameters */); err != nil {
        return nil, err
    }
    defer func() {
        if cErr = r.Close(); cErr != nil {
            err = cErr
        }
    }()
    return err
}

way-2:

func myFn() error {
    var err error
    if r, err = Open(/* parameters */); err != nil {
        return nil, err
    }
    defer func() {
        if cErr = r.Close(); cErr != nil {
            // we can log the error
            // or
            // whatever we want to do
        }
    }()
    return err
}

Я также нашел хороший блог на эту тему, я имею в виду обработку ошибок, когда defer func возвращает ошибку.Проверьте здесь https://blog.learngoprogramming.com/5-gotchas-of-defer-in-go-golang-part-iii-36a1ab3d6ef1.

0 голосов
/ 26 ноября 2018

Сбой изящно с ошибкой.Сообщить о первой ошибке.Не перезаписывайте более ранние ошибки.Например,

package main

import (
    "fmt"
    "os"
)

func demo() (name string, err error) {
    filename := `test.file`
    f, err := os.Open(filename)
    if err != nil {
        return "", err
    }
    defer func() {
        e := f.Close()
        if e != nil {
            if err == nil {
                err = e
            }
        }
    }()

    // do someting with the file
    name = f.Name()
    fi, err := f.Stat()
    if err != nil {
        return name, err
    }
    if fi.Size() == 0 {
        err = fmt.Errorf("%s: empty file", filename)
        return name, err
    }

    return name, err
}

func main() {
    name, err := demo()
    fmt.Println(name, err)
}
0 голосов
/ 26 ноября 2018

Используя defer с func() {}(), вот так.

var r *SomeResource
var err error
if r, err = Open(/* parameters */); err != nil {
    return nil, err
}
defer func() {
    if err = r.Close(); err != nil {
        fmt.Printf("ERROR: %v", err)
    }
}()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...