Golang в настоящее время имеет версию 1.17 (январь 2022 г.). Несмотря на то, что неясно, когда будет выпущен Golang 2.0 и какие функции он включает, есть несколько интересных черновиков, и весьма вероятно, что по крайней мере некоторые из этих черновиков будут частью Golang 2.0. В этой серии я подытожу основные функции Golang 2.0, и мы начнем с обработки ошибок.

Обработка ошибок

Обработка ошибок в Golang — одна из самых обсуждаемых тем. Прямо сейчас Golang заставляет вас — и это хорошо — проверять ошибку после вызова любой функции, которая дает результат в письменной форме.

if (err != nil) {
    return err // or do something else
}

По моему честному мнению, это хорошо, что в Golang есть такая явная проверка ошибок, поскольку она дает вам знать об обработке ошибок. Однако это также приводит к написанию одного и того же кода снова и снова, что не идеально.

В проекте Golang 2.0 об этом позаботились, введя новые ключевые слова check и handler функции. Вместо того, чтобы явно проверять каждую ошибку, вы добавляете ключевое слово check перед функцией, чтобы указать, что эти возвращаемые значения должны быть проверены с помощью функции-обработчика. Небольшой пример будет выглядеть так

func foobar(a, b int) error {
    handle err { return err } // This is our handler
    x := check foo(a, b) // check invokes the handle func
    y := check bar(a, b) // this on as well
    if (x > y) {
        return fmt.Errorf("This is an error")
    }
}

Давайте пройдемся по этому построчно. Сначала мы определяем нашу функцию foobar, которая принимает a и b в качестве входных данных и возвращает ошибку. В следующей строке мы определяем нашу функцию обработки ошибок, обозначенную ключевым словом handle. Функция-обработчик принимает аргумент типа error и имеет ту же сигнатуру возврата, что и объемлющая функция. Таким образом, когда foobar возвращает только ошибку, обработчик может вернуть только ошибку. Если foobar вернет (int, error), функция обработчика должна будет вернуть, например. 0,err.

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

x, err := foo(a, b)
if (err != nil) {
    return err
}

мы пишем только x := check foo(a, b) . Это выполняет тот же поток кода, но не создает никаких дополнительных затрат кода.

Одна приятная особенность обработчиков заключается в том, что вы можете создавать цепочки обработчиков. Давайте посмотрим на следующий код.

func foobar(a, b int) error {
    handle err { return err } // This is our handler
    x := check foo(a, b) // check invokes the first handle func
    y := check bar(a, b) // this on as well
    if (x > y) {
        handle err { err = fmt.Errorf("doSomething with %x and %y, x, y) } // second handler
        check doSomething(x, y) // invokes second handler and then the first
    }
    check doSomething(y, x) // invokes first handler
    return nil
}

Как видно из приведенного выше кода, если мы определим несколько функций-обработчиков, они будут выполняться в обратном порядке. Будьте осторожны, функции-обработчики действительны только для области, в которой они определены. Таким образом, функция-обработчик, определенная в блоке if, будет вызываться только в пределах области.

Предложение по обработке ошибок выглядит многообещающе. Несмотря на то, что сейчас мне нравится явная обработка ошибок в Golang, приятно, что мы можем сократить накладные расходы на код, особенно в больших проектах. Я все еще не уверен, приведет ли это к большей сложности, чем к удобочитаемости, но я с нетерпением жду возможности протестировать это.

Если вас интересуют другие статьи о Golang, ознакомьтесь со следующими статьями.

https://itnext.io/the-power-of-golang-keyword-defer-b31bdecf10b6

Ресурсы

https://go.googlesource.com/proposal/+/master/design/go2draft.md