inline fun <T> rest(request: () -> T): T = try {
request()
} catch (e: HttpException) {
val requestId = e.response().raw().request().header(REQUEST_ID_HEADER)
if (requestId != null) {
Dialog(requestId, R.string.oops).show(fragmentManager, null)
} else {
throw e
}
}
它应该执行一些REST请求(在request
参数中),如果失败,并且它包含指定的HTTP标头,则显示带有该标头的对话框。
但是编译器抱怨Dialog,它没有返回T
,而是返回Unit
。但这基本上就是我想要的!我该怎么办?
一个让我大吃一惊的解决方案是将函数的返回类型设置为T?
并返回null
,但是在Kotlin中,这样做会感到肮脏。
答案 0 :(得分:5)
返回空is not dirty per se。使用null有时会被滥用,但这是使用null的完美有效的用例。 Kotlin允许您以安全,美观的方式使用null,所以请不要害怕使用它!
另一种选择是在显示对话框的情况下(无论标题是否存在)也引发异常。
要进行选择,您必须问自己,如果显示对话框,调用rest()
的代码将执行什么操作。 必须以一种或另一种方式(空或异常)处理T
的缺失。这是因为显示对话框并不能结束函数的执行。
最后但并非最不重要的一点是,还有一个选项可以处理rest()
方法之外的结果。改善Taras的答案:
sealed class Result<out T : Any> {
class Success<out T : Any>(val value: T) : Result<T>()
class ErrorWithId(val exception: Exception, val requestId: String) : Result<Nothing>()
class Error(val exception: Exception) : Result<Nothing>()
}
inline fun <T : Any> rest(request: () -> T): Result<T> = try {
Result.Success(request())
} catch (e: HttpException) {
val requestId = e.response().raw().request().header(REQUEST_ID_HEADER)
if (requestId != null) {
Result.RecoverableError(e, requestId)
} else {
Result.Error(e)
}
}
private fun thingCallingRest() {
val result = rest(::testRequest)
when (result) {
is Result.Success -> Log.v("__DEBUG", "success: ${result.value}")
is Result.ErrorWithId -> Dialog(result.requestId, R.string.oops).show(fragmentManager, null)
is Result.Error -> throw result.exception
}
}
答案 1 :(得分:1)
您可以通过通用的Result
类型来解决它:
sealed class Result<out T : Any> {
class Success<out T : Any>(val value: T) : Result<T>()
class Error(val exception: Exception, val requestId: String?) : Result<Nothing>()
}
inline fun <T : Any> rest(request: () -> T): Result<T> = try {
Result.Success(request())
} catch (e: HttpException) {
val requestId = e.response().raw().request().header(REQUEST_ID_HEADER)
Result.Error(e, requestId)
}
private fun testRest() {
val result = rest(::testRequest)
when (result) {
is Result.Success -> Log.v("__DEBUG", "success: ${result.value}")
is Result.Error -> {
result.requestId?.let {
Dialog(it, R.string.oops).show(fragmentManager, null)
} ?: run {
throw result.exception
}
}
}
}
答案 2 :(得分:0)
一开始返回null可能会很丑,但是有什么选择呢?
选项1:引发异常
如果您需要有关代码失败原因的更多信息,则应引发异常。
让我们以Kotlin的single函数为例:
listOf<Int>().single()
会抛出
NoSuchElementException:列表为空。
listOf<Int>(1, 1).single { it == 1 }
会抛出
IllegalArgumentException:集合包含多个匹配元素。
这就是我提供更多信息的意思。异常的类型和给定的消息可能会为您提供决定如何继续的方式。
选项2:返回null
如果您只是想知道它是否失败,则返回null
是一个很好的信号。甚至Kotlin的标准库都使用singleOrNull()
来做到这一点。
listOf<Int>().singleOrNull() // returns null
使用elvis运算符也可以很简便地提供后备广告:
listOf<Int>().singleOrNull() ?: 1 // default element