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

Wrap a function in try catch using Higher order functions in Kotlin

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


// 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 和函数式编程的新手。

好的!这听起来像是一个合理的设计模式。只是一些注意事项。

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)
}

通过实施你的 Result class 你真的似乎从 stdlib 中复制了一个 class 命名...好吧,Result :-) 你的 safeCall 然后命名为 runCatching:

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

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