假设我们要实现以下计算:
outval/err = f3(f3(f1(inval))
f1
、f2
、f3
中的每一个都可能因错误而失败,此时我们停止计算并设置 err
到失败函数返回的错误。 (当然嵌套可以任意长)
在 C++/JAVA/C# 等语言中,通过 f1
、f2
和 f3
抛出异常并将在 try-catch block 中计算,而在 Haskell 等语言中,我们可以使用 monads 代替。
现在我正在尝试在 GO 中实现它,我能想到的唯一方法是明显的 if-else 阶梯,它相当冗长。如果我们不能嵌套调用,我没有问题,但在我看来,在代码中的每一行之后添加错误检查看起来很难看,并且会破坏流程。我想知道是否有更好的方法。
编辑:根据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)
}
我想说明的是,函数 calc 可能会在可能失败的库函数的帮助下进行一些计算,语义是如果任何调用失败,则 calc 会将错误传播给调用者(类似于不处理异常)。在我看来,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)
}
}
那么我们可以重新定义 calc 为
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)))
}
但如果没有泛型支持,我不确定如何将这种方法用于任何库函数集。
最佳答案
如果你真的希望能够做到这一点,你可以使用 compose 函数。
func compose(fs ...func(Value) (OutVal, error)) func(Value) (OutVal, error) {
return func(val Value) OutVal, Error {
sVal := val
var err error
for _, f := range fs {
sval, err = f(val)
if err != nil {
// bail here and return the val
return nil, err
}
}
return sval, nil
}
}
outVal, err := compose(f1, f2)(inVal)
虽然大多数时候您可能希望比这更直接,因为其他人在遇到您的代码时可能很难理解它。
关于go - GO中的嵌套函数调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10967381/