Есть ли в Kotlin способ объединить встроенную функцию и выражение when с функцией расширения? - PullRequest
4 голосов
/ 11 апреля 2019

Я хотел бы уменьшить размер лестницы if-elseif-else, но не могу использовать только when, потому что smartcast не улавливает случаи, с которыми я имею дело. Мне интересно, могу ли я объединить что-то вроде let или also и when в одну встроенную функцию для решения этой проблемы.

Я пытался использовать умное приведение с is, но это проблематично, потому что мне пришлось бы сделать when внутри внешнего when, чтобы на самом деле получить желаемый результат. Я закончил тем, что делал что-то похожее на один из ответов из этого поста: Котлин и идиоматический способ написания 'если не ноль, иначе ...', основанный на изменяемом значении , просто имея блок let воздействуя на ненулевую переменную, затем выполняя блок when внутри этого let.

Случай, с которым я сейчас работаю:

variable?.let { safeVariable ->
    when {
        case1 -> doSomething(safeVariable)
        case2 -> doSomethingElse(safeVariable)
         ...
        else -> catchAll(safeVariable)
    }
    return@let
}
Log.e(TAG, "variable was null")

Случаи, которые я рассмотрел:

when(variable) {
    is Type -> when {
                   case1 -> doSomething(variable)
                   case2 -> doSomethingElse(variable)
                   ...
                   else -> catchAll(variable)
               }
   else -> Log.e(TAG, "variable was null")
}
if (variable is Type) {
    when {
        case1 -> doSomething(variable)
        case2 -> doSomethingElse(variable)
         ...
        else -> catchAll(variable)
    }
} else {
    Log.e(TAG, "variable was null")
}

То, что я хотел бы написать, выглядело бы так:

variable?.alsoWhen { safeVariable ->
    case1 -> doSomething(safeVariable)
    case2 -> doSomethingElse(safeVariable)
     ...
    else -> catchAll(safeVariable)
} ?: Log.e(TAG, "variable was null")

Можно ли написать на Kotlin с помощью функции расширения, и если нет, то есть хотя бы альтернатива тому, что я написал выше, чтобы сделать его более компактным и читаемым?

EDIT:

Основываясь на комментариях Дэймона ниже, я подумал о несколько более чистом способе подойти к этому:

when(true) { 
    variable?.case1 -> doSomething(variable) 
    variable?.case2 -> doSomethingElse(variable) 
     ... 
    variable is String -> catchAll(variable)
    else -> Log.e(TAG, "variable was null") 
} 

Было бы неплохо, если возможно, избавиться от (true) рядом с буквой, но это достаточно чисто, так что я довольно доволен решением.

1 Ответ

1 голос
/ 11 апреля 2019

Вы можете выполнить приведение внутри аргумента оператора when.

Например,

when (variable as? Type) {
    case1 -> ...
    case2 -> ...
    null -> ...
    else -> ...
}

Другой пример, основанный на комментарии:

enum class UrlType { TYPE_1, TYPE_2, TYPE_3, NULL }

fun String?.urlType(): UrlType {
    return when {
        this?.contains("...") == true -> UrlType.TYPE_1
        this?.startsWith("...") == true -> UrlType.TYPE_2
        this != null -> UrlType.TYPE_3
        else -> UrlType.NULL
    }
}

when (variable.urlType()) {
    UrlType.TYPE_1 -> doSomething()
    UrlType.TYPE_2 -> doSomethingElse()
    UrlType.TYPE_3 -> ...
    UrlType.NULL -> ...
}
...