With Google's official support for Kotlin as the Android development language, Kotlin has been a hot topic lately, but Kotlin doesn't have a ternary operator.
val max = a > b ? a : b // NG
Instead, Kotlin if is treated as an expression, so you can write:
val max = if (a > b) a else b
But isn't it inconvenient that Java has a ternary operator but Kotlin doesn't? : thinking_face: So this time, I'd like to force something like a ternary operator: muscle:
You can't use Operator overloading because Kotlin doesn't have the operators ?
And :
.
However, you can use ʻinfix` to define your own operator (what looks like). https://kotlinlang.org/docs/reference/functions.html#infix-notation
This time, define the class and infix function as follows.
data class TernaryOperation<out T>(val condition: Boolean, val value: T)
infix fun <T> Boolean.`?`(other: T) = TernaryOperation<T>(this, other)
infix fun <T> TernaryOperation<T>.`:`(other: T) = if (this.condition) this.value else other
?
And :
cannot be used as function names, so they are enclosed in backticks.
However, although I could use `?`
, I couldn't use `:`
for some reason, so I chose `:`
(full-width).
Also, in Kotlin, you can use Japanese for function names as in Java, but ? You cannot use
oror
:`.
It looks like this when using the function defined above.
val max = (a > b) `?` a `:` b
It feels like that: sweat_smile:
Kotlin's infix function has a higher priority than the comparison operator. https://kotlinlang.org/docs/reference/grammar.html#precedence
On the other hand, Java ternary operators have a lower priority than comparison operators. https://docs.oracle.com/javase/tutorial/java/nutsandbolts/operators.html
Therefore, if you want to use a comparison operator, etc., like the ternary operator created this time, you need to enclose the conditional expression in parentheses.
Java
int max = a > b ? a : b; // OK
Kotlin
val max = a > b `?` a `:` b // NG
val max = (a > b) `?` a `:` b // OK
val max = (a > b) `?` a + 3 `:` b - 5 // OK
I noticed in the comment of saka1029. Thank you: bow:
Since the ternary operator mock created this time passes a value, both values will be evaluated regardless of the truth of the condition.
Java
int value = array.length > 0 ? array[0] : -1; // OK
Kotlin
val value = array.isNotEmpty() `?` array[0] `:` -1 //ArrayIndexOutOfBoundsException when array is empty
To avoid this, you have to make it ()-> T
type instead of T
type, but it is no longer different from if expression: sweat_smile:
data class TernaryOperation<out T>(val condition: Boolean, val value: () -> T)
infix fun <T> Boolean.`?`(other: () -> T) = TernaryOperation<T>(this, other)
infix fun <T> TernaryOperation<T>.`:`(other: () -> T) = if (this.condition) this.value() else other()
val value = array.isNotEmpty() `?` { array[0] } `:` { -1 } // OK
Define the following infix function.
infix fun <T> Boolean.then(other: T) = if (this) other else null
Using the Elvis operator, you can write it like a ternary operator as follows.
val max = (a > b) then a ?: b
However, if you use null
for the value when true
, it will always be the value when it is false
: cry:
val body = response.isError() then null ?: response.body // always response.body
Also, as before, there are priority issues and expression evaluation issues.
I tried to make it with material, but it's still inconvenient: sweat: I also use Python a lot, so I'm still new to writing Kotlin ternary operators: sob:
If you have any impressions or opinions, please comment: bow:
Recommended Posts