Dla niektórych prostych czynności można skorzystać z sejfu operator call, zakładając działanie poszanowaniem zasady nie działa na pustej listy (do obsługi przypadek zarówno traci puste:
myList?.forEach { ...only iterates if not null and not empty }
przypadku innych działań można napisać funkcję przedłużacza - dwa warianty w zależności czy chcesz otrzymać listę jako this
lub jako parametr.
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)
}
}
które można wykorzystać jako:
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`
}
}
Można również zrobić odwrotną funkcję:
inline fun <E: Any, T: Collection<E>> T?.withNullOrEmpty(func:() -> Unit): Unit {
if (this == null || this.isEmpty()) {
func()
}
}
Wolałbym uniknąć łączenia nich, bo wtedy wymieniasz if
lub when
oświadczenie z czymś bardziej rozwlekły. A ty wchodzisz w sferę, o której wspomniałem w poniższych alternatywach, czyli pełne rozgałęzienia dla sytuacji sukcesu/porażki.
Uwaga: rozszerzenia zostały uogólnione na wszystkich potomków Collections
z wartościami niepustymi. Pracuj więcej niż tylko Listy.
Alternatywy:
Result biblioteki Kotlin daje przyjemny sposób obsłużyć swój przypadek „to zrobić, albo, że” na podstawie wartości odpowiedzi. W przypadku obietnic można znaleźć to samo w bibliotece Kovenant.
Obie te biblioteki dają sposób zwracania alternatywnych wyników z pojedynczej funkcji, a także rozgałęzienia kodu na podstawie wyników. Wymagają one, aby kontrolować dostawcę "odpowiedzi", na którą działa.
To są dobre alternatywy dla Kotlin dla Optional
i Maybe
.
Odkrywając Funkcje rozszerzeń Dalsze (a może zbyt dużo)
Ta sekcja jest po prostu pokazać, że kiedy trafisz problem podobny do kwestii podniesionej tutaj, można łatwo znaleźć wiele odpowiedzi w Kotlin, aby kodowanie tak, jak chcesz. Jeśli świat nie jest sympatyczny, zmień świat. Nie jest pomyślana jako dobra lub zła odpowiedź, ale raczej jako dodatkowa informacja.
Jeśli lubisz funkcji rozszerzających i rozważyć łączenia ich w wyrażeniu, to pewnie je zmienić w następujący sposób ...
The withXyz
smaki wrócić this
i whenXyz
powinien powrócić nowy typ pozwalający cała kolekcja stanie się nowa (może nawet niezwiązana z oryginałem). Powstały w kodzie jak poniżej:
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")
}
}
Uwaga: pełny kod dla tej wersji znajduje się na końcu tego postu (1)
Ale można też pójść zupełnie nowy kierunek w zwyczaju " to inaczej, że”mechanizm:
fun foo(someList: List<String>?) {
someList.whenNullOrEmpty {
// other code
}
.otherwise { list ->
// do something with `list`
}
}
nie ma żadnych ograniczeń, być kreatywnym i nauczyć moc rozszerzeń, spróbować nowych pomysłów, a jak widać istnieje wiele odmian tego, jak ludzie chcą, aby zakodować tego typu sytuacjach . Stdlib nie obsługuje 8 odmian tego typu metod, nie wprowadzając zamieszania. Ale każda grupa programistów może mieć rozszerzenia pasujące do ich stylu kodowania.
Uwaga: pełny kod dla tej wersji znajduje się na końcu tego postu (2)
Przykładowy kod 1:Oto pełny kod dla „przykuty” wersji:
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
}
Przykładowy kod 2:Oto pełny kod dla „to inaczej że”biblioteki (z badanej jednostki):
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
}
UWAGA: 'when' z dwóch alternatyw jest bardzo zbliżony do normalnego' if' –