Imagine a function like this:
fun foo(bar: Bar) {
val bar2: Bar = bar.nullableThing ?: return
// do something with bar2
}
This works perfectly until you want to run something (like showing a message) before that "return" statement. I think it would look like this:
fun foo(bar: Bar) {
val bar2: Bar = bar.nullableThing ?: run {
println("Error!")
return
}
// do something with bar2
}
but that does not work ('return' is not allowed here
).
Edit: My issue was actually with the continue statement, I did not know this would work with return. Here is a new piece of code that is more similar to the actual code:
data class Item(val str: String?)
val items = listOf<Item>(Item("tag:a"), Item("tag:b"), Item(null), Item("tag:c"))
val taggedItems = mapOf<String, String>("a" to "ItemA", "b" to "ItemB")
fun main() {
for (item in items) {
val stringItem = item.str?.let {
if (it.startsWith("tag:")) taggedItems[it.substringAfter("tag:")]
else it
} ?: run {
println("Error: tag ${item.str} is invalid")
continue
}
compute(stringItem)
}
}
fun compute(itemStr: String) = println(itemStr)
https://pl.kotl.in/SSU_z-Ctu
The error is 'break' or 'continue' jumps across a function or a class boundary
.
Given this, I could create a function like this:
fun printError(item: Item): String? {
println("Error: tag ${item.str} is invalid")
return null
}
And then
... ?: printError(item) ?: continue
butt that would be awful
CodePudding user response:
You could just revert to traditional coding style:
fun main() {
for (item in items) {
val stringItem = item.str?.let {
if (it.startsWith("tag:")) taggedItems[it.substringAfter("tag:")]
else it
}
if (stringItem == null) {
println("Error: tag ${item.str} is invalid")
continue
}
// From here on, stringItem is smart-cast as non-nullable
compute(stringItem)
}
}
Though I would personally prefer avoiding anything that behaves similarly to a goto, such as continue
:
fun main() {
for (item in items) {
val stringItem = item.str?.let {
if (it.startsWith("tag:")) taggedItems[it.substringAfter("tag:")]
else it
}
if (stringItem != null) {
compute(stringItem)
} else {
println("Error: tag ${item.str} is invalid")
}
}
}
But if you really, really like to use scope functions as much as possible:
fun main() {
for (item in items) {
item.str?.let {
if (it.startsWith("tag:")) taggedItems[it.substringAfter("tag:")]
else it
}.also {
compute(it)
} ?: println("Error: tag ${item.str} is invalid")
}
}