【问题标题】:Wrap a function in try catch using Higher order functions in Kotlin使用 Kotlin 中的高阶函数在 try catch 中包装函数
【发布时间】:2021-11-02 14:55:46
【问题描述】:

我有一组具有不同签名和参数的函数,但它们都可能引发异常。我不想在每个函数中添加 try-catch,而是编写一个内联函数,该函数将函数作为参数并在 try-catch 块中调用此函数,并返回包含异常的某些类型。


// first function. 
fun foo() -> String

// second function. 
fun bar(argument: String) -> Boolean


// Result Type
sealed class Result<out R> {
    data class Success<out T>(val data: T) : Result<T>()
    data class Error(val exception: Exception) : Result<Nothing>()
}

// Wrapper Function
inline fun <T, R> safeCall(call: (T) -> R): Result<R>


// This Returns Result<String>
safeCall { 
    foo()
}

// This Returns Result<Boolean>
safeCall { 
    bar()
}

我在实现safeCall() 方法时遇到了问题。理想情况下,我希望它适用于任何基础功能。我可以让它为foo()bar(argument: String) 工作,但不能同时为两者工作。

inline fun <T, R> safeCall(
    call: (T) -> R, // This syntax forces to to have only one parameter.
): Result<R> {
    return try {
        val result: R = call() // This throws compilation error. 
        Result.Success(result)
    } catch (e: Exception) {
        Result.Error(e)
    }
}

PS - Kotlin 和函数式编程的新手。

【问题讨论】:

  • 我没有看到一个问题,这是一个修辞论证吗?

标签: kotlin generics functional-programming higher-order-functions


【解决方案1】:

通过实现您的Result 类,您似乎确实从stdlib 中复制了一个名为...的类...好吧,Result :-) 您的safeCall 然后被命名为runCatching

// Result<String>
runCatching {
    foo()
}

// Result<Boolean>
runCatching {
    bar("Example Argument")
}

【讨论】:

  • 谢谢。 runCatching() 似乎正是我想要实现的。感谢您提出这个建议。我将开始使用它。我打算使这个函数非内联,并通过采用另一个内联函数来捕获错误并在其上生成错误消息。但我认为在这里制作一个 Exception 的扩展函数来获得有意义的有趣错误消息会更有意义。
【解决方案2】:

当然!这听起来像是一个合理的设计模式。只是一些笔记。

inline fun <T, R> safeCall(call: (T) -> R): Result<R>

safeCall 的参数本身不应该需要参数。这只是我们要调用的一段代码,所以这将是一个更合适的签名。

inline fun <R> safeCall(call: () -> R): Result<R>

现在至于如何实际实施它,听起来您已经有了所有正确的想法。只需尝试在实际的 Kotlin try 块内调用函数。

inline fun <R> safeCall(call: () -> R): Result<R> {
  try {
    return Result.Success(call())
  } catch (e: Exception) {
    return Result.Error(e)
  }
}

那么你可以称它为

safeCall { 
  foo()
}

safeCall { 
  bar("Example Argument")
}

记住bar 接受一个参数。即使该参数是在safeCall 范围之外定义的,它仍然可以通过闭包的魔力发挥作用。

val x = "This works :)"
safeCall { 
  bar(x)
}

【讨论】:

  • 谢谢,@Silvio。这正是我想要的。我在 call() 中传递了一个通用的 时犯了一个错误,迫使我只传递一个参数。
猜你喜欢
  • 2017-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-23
  • 1970-01-01
  • 2017-02-15
  • 1970-01-01
  • 2021-05-10
相关资源
最近更新 更多