在 Kotlin 中使用高阶函数将函数包装在 try catch 中

bpr*_*r10 5 generics functional-programming higher-order-functions kotlin

我有一组具有不同签名和参数的函数,但它们都可能抛出异常。我不想在每个函数中添加 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()
}
Run Code Online (Sandbox Code Playgroud)

我在实施该方法时遇到问题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)
    }
}
Run Code Online (Sandbox Code Playgroud)

PS - Kotlin 和函数式编程相当陌生。

Sil*_*olo 4

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

inline fun <T, R> safeCall(call: (T) -> R): Result<R>
Run Code Online (Sandbox Code Playgroud)

safeCall的论证本身不应该需要论证。这只是我们要调用的代码块,因此这将是一个更合适的签名。

inline fun <R> safeCall(call: () -> R): Result<R>
Run Code Online (Sandbox Code Playgroud)

至于如何实际实施,听起来你的想法都是正确的。只需尝试在实际的 Kotlin 块内调用该函数即可try

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

然后你可以将其称为

safeCall { 
  foo()
}

safeCall { 
  bar("Example Argument")
}
Run Code Online (Sandbox Code Playgroud)

请记住,这bar需要争论。即使该参数是在safeCall范围之外定义的,它仍然可以通过闭包的魔力起作用。

val x = "This works :)"
safeCall { 
  bar(x)
}
Run Code Online (Sandbox Code Playgroud)