Допустим, мы хотим реализовать следующие вычисления:Вложенные вызовы функций в GO
outval/err = f3(f3(f1(inval))
, где каждый из f1
, f2
, f3
может потерпеть неудачу с ошибкой в то время мы прекращаем расчет и установить err
к ошибке, возвращаемой функцией сбоя. (Конечно, раскрой может быть сколь угодно долго)
В таких языках, как C++/Java/C# это можно легко сделать, имея f1
, f2
и f3
сгенерирует исключение и ограждающих вычисления в примерочных поймать блока, в то время как в такие языки, как Haskell, мы можем использовать вместо них монады.
Теперь я пытаюсь реализовать его в GO, и единственный подход, о котором я могу думать, - это очевидная лестница if-else, которая довольно многословна. У меня нет проблем, если мы не можем вложить вызовы, но, на мой взгляд, добавить проверку ошибок после того, как каждая строка в коде выглядит уродливой и она прерывает поток. Я хотел бы знать, есть ли лучший способ сделать это.
Edit: Редактирование в соответствии с комментарием по peterSO
Ниже приведен конкретный пример и прямой реализации
package main
import "fmt"
func f1(in int) (out int, err error) {
return in + 1, err
}
func f2(in int) (out int, err error) {
return in + 2, err
}
func f3(in int) (out int, err error) {
return in + 3, err
}
func calc(in int) (out int, err error) {
var temp1, temp2 int
temp1, err = f1(in)
if err != nil {
return temp1, err
}
temp2, err = f2(temp1)
if err != nil {
return temp2, err
}
return f3(temp2)
}
func main() {
inval := 0
outval, err := calc3(inval)
fmt.Println(inval, outval, err)
}
То, что я пытаюсь проиллюстрировать это, функция известково делает некоторые вычисления, возможно, с помощью функций библиотеки что может произойти сбой и семантика, если какой-либо вызов fail calc распространяет ошибку на вызывающего абонента (аналогично тому, как обрабатывать исключение). На мой взгляд, код для расчета является уродливым.
Между для данного конкретного случая, когда все функции библиотеки имеют точно такую же подпись, мы можем сделать код лучше (я использую идею из http://golang.org/doc/articles/wiki/#tmp_269)
func saferun(f func (int) (int, error)) func (int, error) (int, error) {
return func (in int, err error) (int, error) {
if err != nil {
return in, err
}
return f(in)
}
}
Тогда мы можем переопределить известково, как
func calc(in int) (out int, err error) {
return saferun(f3)(saferun(f2)(f1(in)))
}
или
func calc(in int) (out int, err error) {
sf2 := saferun(f2)
sf3 := saferun(f3)
return sf3(sf2(f1(in)))
}
Но без дженериков с upport, я не уверен, как я могу использовать этот подход для любого набора функций библиотеки.
Спасибо, что ответили, но я не уверен, что понимаю ваш подход. Что делать, если я не контролирую подпись f1, f2, f3 и т. Д., Потому что они являются библиотечными функциями.В моем скромном мнении ошибки обработки инфраструктур на других языках не требуют, чтобы у вас был такой контроль – Suyog
Suyog, цитируя ваш исходный вопрос: «... сделанный путем исключения f1, f2 и f3 исключения». похоже, что вы разрешаете изменять f1, f2 и f3 для исключения исключений. Их паника ничем не отличается. Паника - это механизм, доступный в Go, чтобы разматывать стек с произвольной глубины, возвращая значение в процессе. Это не идиоматический и предпочтительный способ обработки ошибок в Go, но именно механизм будет делать то, что вы просите. – Sonia
Я имел в виду, что f1, f2, f3 уже определены для исключения. Извините за плохую формулировку. На языке, подобном JAVA, многие функции библиотеки определены для исключения исключений, тогда как в GO это выглядит так, чтобы функции библиотеки возвращали ошибку. Поэтому проблема, с которой я столкнулась, - это проверить ошибки сразу, что приводит к написанию повторяющегося кода. – Suyog