Как сделать функцию, которая проглатывает исключения - PullRequest
0 голосов
/ 21 февраля 2019
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, отобразить диалоговое окно с этим заголовком.

Но компилятор жалуется настрока с диалогом, что он не возвращает T, но Unit.Но это в основном то, что я хочу!Как я могу это сделать?

Одно решение, которое приходит мне в голову: установить тип возвращаемого значения функции T? и вернуть null, но он чувствует, что грязный делает это в Котлине.

Ответы [ 3 ]

0 голосов
/ 21 февраля 2019

Возвращает ноль не является грязным само по себе .Иногда можно злоупотреблять использованием нулей, но это вполне допустимый вариант использования нуля.Kotlin позволяет вам использовать null безопасным и приятным способом, так что не бойтесь его использовать!

Другой вариант - вызвать исключение также в том случае, если вы показываете диалоговое окно (независимо от того, есть ли заголовок или нет).присутствует).

Чтобы выбрать, вам нужно спросить себя, что будет делать код, вызывающий rest(), если появится диалоговое окно. имеет , чтобы так или иначе иметь дело с отсутствием T (ноль или исключение).Это связано с тем, что показ диалога не является чем-то, что прекращает выполнение вашей функции.

И последнее, но не менее важное, есть также возможность работать с результатом вне метода rest().Улучшение в ответе Тараса:

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
    }
}
0 голосов
/ 21 февраля 2019

Возвращение null поначалу может показаться уродливым, но каковы варианты?

Вариант 1: создание исключения

Если вам нужна дополнительная информация о том, почему кодне удалось создать исключение.

Давайте рассмотрим в качестве примера single функцию Котлина:

listOf<Int>().single() 

выбросит

NoSuchElementException: список пуст.

listOf<Int>(1, 1).single { it == 1 } 

выбросит

IllegalArgumentException: Коллекция содержит более одного совпадающего элемента.

Thisэто то, что я имею в виду с дополнительной информацией.Тип исключения и данное сообщение могут предоставить вам способы решить, как продолжить.

Вариант 2: Возврат null

В случае, если вы просто хотите узнать,не удалось или не вернул null, это хороший способ сигнализировать об этом.Даже стандартная библиотека Kotlin делает это, например, с помощью singleOrNull().

listOf<Int>().singleOrNull() // returns null

Обеспечение возврата также очень лаконично с помощью оператора elvis:

listOf<Int>().singleOrNull() ?: 1 // default element
0 голосов
/ 21 февраля 2019

Вы можете решить это по типу 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
            }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...