Для некоторых простых действий, вы можете использовать оператор безопасного вызова, предполагая, что действие также уважает не работает на пустом список (для обработки вашего случая как утративших пусто:
myList?.forEach { ...only iterates if not null and not empty }
для других действий, которые вы можете написать функцию расширения - два варианта в зависимости от того, если вы хотите получить список в качестве this
или в качестве параметра:.
inline fun <E: Any, T: Collection<E>> T?.withNotNullNorEmpty(func: T.() -> Unit): Unit {
if (this != null && this.isNotEmpty()) {
with (this) { func() }
}
}
inline fun <E: Any, T: Collection<E>> T?.whenNotNullNorEmpty(func: (T) -> Unit): Unit {
if (this != null && this.isNotEmpty()) {
func(this)
}
}
Что вы можете использовать как:
fun foo() {
val something: List<String>? = makeListOrNot()
something.withNotNullNorEmpty {
// do anything I want, list is `this`
}
something.whenNotNullNorEmpty { myList ->
// do anything I want, list is `myList`
}
}
Вы можете также сделать обратную функцию:
inline fun <E: Any, T: Collection<E>> T?.withNullOrEmpty(func:() -> Unit): Unit {
if (this == null || this.isEmpty()) {
func()
}
}
Я бы избежать сцепления их, потому что тогда вы заменяете if
или when
о чем-то более многословие. И вы получаете больше в область, которую предоставляют ниже альтернативы, о которых я упоминаю ниже, что является полным ветвлением для ситуаций успеха/неудачи.
Примечание: эти расширения были обобщены на всех потомков Collections
, содержащих непустые значения. И работайте больше, чем просто списки.
Альтернатива:
Result библиотека для Котлина дает хороший способ справиться с вашим случаем «сделать это, или что» на основе значений отклика. Для Promises вы можете найти то же самое в библиотеке Kovenant.
Обе эти библиотеки дают вам возможность возвращать альтернативные результаты из одной функции, а также для разветвления кода на основе результатов. Они требуют, чтобы вы контролировали поставщика «ответа», на который воздействовали.
Это хорошие альтернативы Котлин для Optional
и Maybe
.
Изучение функций расширения Далее (и, возможно, слишком много)
Этот раздел только, чтобы показать, что, когда вы нажмете вопрос, как вопрос, поднятый здесь, вы можете легко найти ответы на многие вопросы в Котлин, чтобы сделать кодируя то, как вы хотите. Если мир не нравится, измените мир. Это не является хорошим или плохим ответом, а скорее дополнительной информацией.
Если вы любите функции расширения и рассмотреть возможность их сцепления в выражении, я бы, вероятно, изменить их следующим образом ...
The withXyz
ароматы вернуть this
и whenXyz
должен возвращать новый тип, позволяющий вся коллекция станет новой (возможно, даже не связанной с оригиналом). В результате в коде, как в следующем:
val BAD_PREFIX = "abc"
fun example(someList: List<String>?) {
someList?.filterNot { it.startsWith(BAD_PREFIX) }
?.sorted()
.withNotNullNorEmpty {
// do something with `this` list and return itself automatically
}
.whenNotNullNorEmpty { list ->
// do something to replace `list` with something new
listOf("x","y","z")
}
.whenNullOrEmpty {
// other code returning something new to replace the null or empty list
setOf("was","null","but","not","now")
}
}
Примечание: полный код для этой версии в конце поста (1)
Но вы могли бы также пойти совершенно новое направление с обычаем " это иначе, что»механизм:
fun foo(someList: List<String>?) {
someList.whenNullOrEmpty {
// other code
}
.otherwise { list ->
// do something with `list`
}
}
там нет никаких ограничений, быть творческим и узнать силу расширений, попробовать новые идеи, и как вы можете видеть, что есть много вариантов, как люди хотят, чтобы закодировать эти типы ситуаций , Stdlib не может поддерживать 8 вариантов этого типа методов, не запутывая. Но каждая группа разработчиков может иметь расширения, соответствующие их стилю кодирования.
Примечание: Полный код для этой версии в конце поста (2)
Пример кода 1:Вот полный код «прикован» версии:
inline fun <E: Any, T: Collection<E>> T?.withNotNullNorEmpty(func: T.() -> Unit): T? {
if (this != null && this.isNotEmpty()) {
with (this) { func() }
}
return this
}
inline fun <E: Any, T: Collection<E>, R: Any> T?.whenNotNullNorEmpty(func: (T) -> R?): R? {
if (this != null && this.isNotEmpty()) {
return func(this)
}
return null
}
inline fun <E: Any, T: Collection<E>> T?.withNullOrEmpty(func:() -> Unit): T? {
if (this == null || this.isEmpty()) {
func()
}
return this
}
inline fun <E: Any, T: Collection<E>, R: Any> T?.whenNullOrEmpty(func:() -> R?): R? {
if (this == null || this.isEmpty()) {
return func()
}
return null
}
Пример кода 2:Вот полный код для «это иначе что»библиотека (с блоком тестирования):
inline fun <E : Any, T : Collection<E>> T?.withNotNullNorEmpty(func: T.() -> Unit): Otherwise {
return if (this != null && this.isNotEmpty()) {
with (this) { func() }
OtherwiseIgnore
} else {
OtherwiseInvoke
}
}
inline fun <E : Any, T : Collection<E>> T?.whenNotNullNorEmpty(func: (T) -> Unit): Otherwise {
return if (this != null && this.isNotEmpty()) {
func(this)
OtherwiseIgnore
} else {
OtherwiseInvoke
}
}
inline fun <E : Any, T : Collection<E>> T?.withNullOrEmpty(func:() -> Unit): OtherwiseWithValue<T> {
return if (this == null || this.isEmpty()) {
func()
OtherwiseWithValueIgnore<T>()
} else {
OtherwiseWithValueInvoke(this)
}
}
inline fun <E : Any, T : Collection<E>> T?.whenNullOrEmpty(func:() -> Unit): OtherwiseWhenValue<T> {
return if (this == null || this.isEmpty()) {
func()
OtherwiseWhenValueIgnore<T>()
} else {
OtherwiseWhenValueInvoke(this)
}
}
interface Otherwise {
fun otherwise(func:() -> Unit): Unit
}
object OtherwiseInvoke : Otherwise {
override fun otherwise(func:() -> Unit): Unit {
func()
}
}
object OtherwiseIgnore : Otherwise {
override fun otherwise(func:() -> Unit): Unit {
}
}
interface OtherwiseWithValue<T> {
fun otherwise(func: T.() -> Unit): Unit
}
class OtherwiseWithValueInvoke<T>(val value: T) : OtherwiseWithValue<T> {
override fun otherwise(func: T.() -> Unit): Unit {
with (value) { func() }
}
}
class OtherwiseWithValueIgnore<T> : OtherwiseWithValue<T> {
override fun otherwise(func: T.() -> Unit): Unit {
}
}
interface OtherwiseWhenValue<T> {
fun otherwise(func: (T) -> Unit): Unit
}
class OtherwiseWhenValueInvoke<T>(val value: T) : OtherwiseWhenValue<T> {
override fun otherwise(func: (T) -> Unit): Unit {
func(value)
}
}
class OtherwiseWhenValueIgnore<T> : OtherwiseWhenValue<T> {
override fun otherwise(func: (T) -> Unit): Unit {
}
}
class TestBrancher {
@Test fun testOne() {
// when NOT null or empty
emptyList<String>().whenNotNullNorEmpty { list ->
fail("should not branch here")
}.otherwise {
// sucess
}
nullList<String>().whenNotNullNorEmpty { list ->
fail("should not branch here")
}.otherwise {
// sucess
}
listOf("a", "b").whenNotNullNorEmpty { list ->
assertEquals(listOf("a", "b"), list)
}.otherwise {
fail("should not branch here")
}
// when YES null or empty
emptyList<String>().whenNullOrEmpty {
// sucess
}.otherwise { list ->
fail("should not branch here")
}
nullList<String>().whenNullOrEmpty {
// success
}.otherwise {
fail("should not branch here")
}
listOf("a", "b").whenNullOrEmpty {
fail("should not branch here")
}.otherwise { list ->
assertEquals(listOf("a", "b"), list)
}
// with NOT null or empty
emptyList<String>().withNotNullNorEmpty {
fail("should not branch here")
}.otherwise {
// sucess
}
nullList<String>().withNotNullNorEmpty {
fail("should not branch here")
}.otherwise {
// sucess
}
listOf("a", "b").withNotNullNorEmpty {
assertEquals(listOf("a", "b"), this)
}.otherwise {
fail("should not branch here")
}
// with YES null or empty
emptyList<String>().withNullOrEmpty {
// sucess
}.otherwise {
fail("should not branch here")
}
nullList<String>().withNullOrEmpty {
// success
}.otherwise {
fail("should not branch here")
}
listOf("a", "b").withNullOrEmpty {
fail("should not branch here")
}.otherwise {
assertEquals(listOf("a", "b"), this)
}
}
fun <T : Any> nullList(): List<T>? = null
}
Примечание: а 'when' с двумя альтернативами очень близко к нормальному' if' –