go - GO中的嵌套函数调用

标签 go

假设我们要实现以下计算:

outval/err = f3(f3(f1(inval))

f1f2f3 中的每一个都可能因错误而失败,此时我们停止计算并设置 err 到失败函数返回的错误。 (当然嵌套可以任意长)

在 C++/JAVA/C# 等语言中,通过 f1f2f3 抛出异常并将在 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/

相关文章:

go - 使用缓冲 IO 与使用 Goroutine 写入文件

go - 如何在 Golang 中添加/编辑文件元数据?

.htaccess - Heroku htaccess 基本身份验证上的 Golang 应用程序

testing - 如何在测试中运行示例?

mysql - 未选择 Golang MySQL 数据库

go - 模板中的结构数组

memory-management - Go(lang) 内存使用 : RSIZE growing and VSIZE of 139GB?

macos - 安全 : SecKeychainSearchCopyNext Error - Unable to Install Delve on MacOS

go - 从大文件中删除特定行的最快方法是什么?

pointers - 如何将* uint64和* uint32数据类型转换为int数据类型?