Kotlin Ternary条件演算子


回答:


617

Kotlinでは、ifステートメントは式です。したがって、次のコードは同等です。

if (a) b else c

ここでは、式とステートメントの区別が重要です。Java / C#/ JavaScriptではif、ステートメントを形成します。つまり、値に解決されません。具体的には、変数に代入することはできません。

// Valid Kotlin, but invalid Java/C#/JavaScript
var v = if (a) b else c

ifステートメントがである言語から来ている場合、これは不自然に見えるかもしれませんが、その感覚はすぐに収まるはずです。


57
さらに、を使用できますwhen
bashor

5
追加するだけで、ブール式の場合は、次のようにすることもできますx = a==b
gnomeria

2
@MikeRylanderこれを明確にするために答えを拡張しました。これを指摘してくれてありがとう。
Drew Noakes 2017

1
@AdeelAnsariいいえ、修正されていません。悪いです。これを比較してください。b + if (a) c else db + (c if (a) else d)後者は追加の括弧が必要です。c条件に囲まれていないためですelse
Naetmul 2018年

1
このトピックについて少し説明します。ディスカッション.kotlinlang.org / t / ternary
F.ノーバート

70

独自に定義できBoolean戻っという拡張機能をですが、三項演算子と同様の構造を提供します。nullBooleanfalse

infix fun <T> Boolean.then(param: T): T? = if (this) param else null

これにより、次のようにa ? b : c式がに変換されa then b ?: cます。

println(condition then "yes" ?: "no")

更新: しかし、さらにJavaのような条件付きスイッチを実行するには、そのようなものが必要になります

infix fun <T> Boolean.then(param: () -> T): T? = if (this) param() else null

println(condition then { "yes" } ?: "no") ラムダに注意してください。その内容の計算は、確認するまで延期する必要がありますconditionがありますtrue

これはぎこちないように見えます。そのためJavaの三項演算子をKotlinに移植するという要求の強い要求があります。


1
infix inline fun<T> Boolean.then(param: ()->T):T? = if(this) param() else null
nullbyte '19年

3
使用<T:任意>、そうでない場合は正しく動作します:true then { null } ?: "not-null"
ユージン・ペトレンコ

ところで、?:ここのオペレーターはelvis-operatorkotlinlang.org/docs/reference/null-safety.html#elvis-operator
Eric Wang

64

TL; DR

if (a) b else c

三項演算子式の代わりに使用できるものですa ? b : c


Kotlinでは、を含む多くの制御ステートメントifwhenまたはtryとしても使用できます。これは、それらが変数に割り当てられたり、関数などから返されたりする結果を持つ可能性があることを意味します。

構文的には、三項演算子は必要ありません

Kotlinの式の結果として、言語は実際には三項演算子を必要としません

if (a) b else c

三項演算子式の代わりに使用できるものですa ? b : c

誰もが何を知っているので、前の表現はもっと読みやすいという考えだと思います ifelseが、? :既に構文に慣れていないのであれば、むしろ不明です。

それにもかかわらず、私はより便利な三項演算子をしばしば見逃していることを認めざるを得ません。


他の選択肢

いつ

またwhen、条件がチェックされるときにKotlinで使用される構成が表示される場合もあります。また、if-elseカスケードを別の方法で表現する方法でもあります。以下は、OTの例に対応しています。

when(a) {
    true -> b
    false -> c
}

拡張

他の回答の多くの良い例(Kotlin Ternary Conditional Operator)が示すように、拡張機能はユースケースの解決にも役立ちます。


36

私自身は、次の拡張関数を使用しています。

fun T?.or<T>(default: T): T = if (this == null) default else this 
fun T?.or<T>(compute: () -> T): T = if (this == null) compute() else this

1つ目は、オブジェクトがnullの場合に提供されたデフォルト値を返します。2番目は、同じケースでラムダで提供される式を評価します。

使用法:

1) e?.getMessage().or("unknown")
2) obj?.lastMessage?.timestamp.or { Date() }

個人的には、上記のコードはif構文のインライン化よりも読みやすい


34
これは、という質問に関連していないのですが、なぜ使用しない:? エルビス演算子?最初の関数はに置き換えられe.getMessage() ?: "unknown"ます。2番目は次のように表すことができますobj?.lastMessage?.timestamp ?: { Date() }()
ホットキー2015

1
@hotkeyには特別な目的はありません。私の観点から見ると、構造を括弧で
囲む

14
@ruX elvisオペレーターは特にこれを目的としており、あなたの使用はかなり珍しいものです。
Jayson Minard、2015

6
?:は問題ありませんが、Perlへの道のりはそれほど遠くまで行きません。
Richard Haven


28

ブロックは値を返すため、kotlinには三項演算子はありませんif else

だから、あなたは行うことができます: val max = if (a > b) a else b javaの代わりにmax = (a > b) ? b : c

when構築を使用することもでき、値も返します。

val max = when(a > b) {
    true -> a
    false -> b
}

ここにkotlinのドキュメントへのリンクがあります:制御フロー:if、when、for、while


27

Kotlinでは、ifは式です。つまり、値を返します。したがって(condition ? then : else)、通常のifがこの役割でうまく機能するため、三項演算子はありません。 ここから手動ソース

// Traditional usage 
var max = a 
if (a < b) max = b

// With else 
var max: Int
if (a > b) {
    max = a
} else {
    max = b
}

// As expression 
val max = if (a > b) a else b

26

他の回答で言及されていないいくつかのコーナーケース。

出現以来takeIfKotlin 1.1三オペレータはa ? b : c、このように表現することができます。

b.takeIf { a } ?: c

cがnull次の場合、これはさらに短くなります。

b.takeIf { a }

また、Javaの世界はnullチェックの典型的には好きなことをノートvalue != null ? value : defaultValueだけにideomatic Kotlinに変換しますvalue ?: defaultValue

同様にa != null ? b : cに翻訳できますa?.let { b } ?: c


6
どれほどb.takeIf { a } ?: c短くて読みやすいですif (a) b else cか?Terneray演算子は確かに変数名からKotlinで不足している機能であり、状態が長くなると、あなたが悪いの行を分割することができます
ジャヴァドSadeqzadeh

1
また、 takeIf常にtrue-caseを評価する(ここa)。aたまたま偽の場合、その式が無用に計算される可能性があるだけでなく、スマートキャストアラの恩恵を受けることもできませんif (a is Int) { a + 3 }
TheOperator

@TheOperator、間違っています。{ a }遅延評価されたラムダです。
Vadzim 2018

1
私はそれを間違って書きました、「常に本当のケースを評価します(ここb)」。しかし、でも{ a }、怠惰であるにもかかわらず、式の結果を決定するために評価する必要あります。
TheOperator 2018

24

ドキュメントを見てください:

Kotlinでは、ifが式、つまり値を返します。したがって、通常のifがこの役割でうまく機能するため、3項演算子(条件?then:else)はありません。



12

タスク

次の例を考えてみましょう:

if (!answer.isSuccessful()) {
    result = "wrong"
} else {
    result = answer.body().string()
}
return result

Kotlinには次の同等のものが必要です。

return(!answer.isSuccessful()) ? "間違った" : answer.body()。string()


ソリューション

1.Aif-expressionKotlinで使用できます。

return if (!answer.isSuccessful()) "wrong" else answer.body().string()

1.B。これをひっくり返すと、はるかに良くなりますif-expression(なしでやりましょうnot):

return if (answer.isSuccessful()) answer.body().string() else "wrong"

。KotlinのElvisオペレーター?:は、より良い仕事をすることができます:

return answer.body()?.string() ?: "wrong"

。またはExtension function、対応するAnswerクラスにを使用します。

fun Answer.bodyOrNull(): Body? = if (isSuccessful()) body() else null

。を使用すると、Extension function次のおかげでコードを削減できますElvis operator

return answer.bodyOrNull()?.string() ?: "wrong"

。または単にwhen演算子を使用します:

when (!answer.isSuccessful()) {
    parseInt(str) -> result = "wrong"
    else -> result = answer.body().string()
}

お役に立てれば。


11

Cのような言語のスイッチ演算子を置き換える場合。最も単純な形では次のようになります

when (x) {
    1 -> print("x == 1")
    2 -> print("x == 2")
    else -> {
        print("x is neither 1 nor 2")
    }
}

3
確かに、しかし、あなたが示す例whenはステートメントではなく、式として持っています。三項条件式とのより適切な比較は、各ブランチに値を返すようにすることです。これにより、(三項条件式で発生するように)when式全体が値に評価されます。
Drew Noakes

9

Kotlinには三項演算子はありません。一見問題があるようです。しかし、これはここでの式なので、インラインif elseステートメントで実行できると思います。単に私たちがしなければならない-

var number = if(n>0) "Positive" else "Negetive"

ここで、必要な数だけブロックしすぎると、他のことができます。お気に入り-

var number = if(n>0) "Positive" else if(n<0) "Negative" else "Zero"

したがって、この行は三項演算子よりも単純で読みやすいものです。Javaで複数の三項演算子を使用すると、恐ろしいように見えます。しかし、ここには明確な構文があります。複数行で書くこともできます。


9

var a= if (a) b else c三項演算子の代わりに使用できます。

Kotlinのもう1つの優れた概念は、Elvisオペレーターです。毎回nullをチェックする必要はありません。

val l = b?.length ?: -1

bがnullでない場合は長さを返し、そうでない場合は右側のステートメントを実行します。


7

Drew Noakesが引用したように、kotlinはifステートメントを式として使用するため、三項条件演算子はもう必要ありません。

しかし、拡張関数とインフィックスのオーバーロードを使用すると、自分で実装できます。ここに例があります

infix fun <T> Boolean.then(value: T?) = TernaryExpression(this, value)

class TernaryExpression<out T>(val flag: Boolean, val truly: T?) {
    infix fun <T> or(falsy: T?) = if (flag) truly else falsy
}

次に、このように使用します

val grade = 90
val clazz = (grade > 80) then "A" or "B"

たぶん<T>をより良く削除しますか?infix fun or(falsy:T?)= if(flag)else else falsy
solo

1
しかし、<T>を追加すると機能します:(グレード> 80)次にnullまたは "B"
ソロ

これは本当にクールです。私はそれを使用します。大したことではありませんが、ゼロコストの抽象化ではないことを知っておく価値はあります。
アダム

6

別の興味深いアプローチは、使用することwhenです:

when(a) {
  true -> b
  false -> b
}

より複雑なシナリオでは非常に便利です。そして正直なところ、私にとってはif ... else ...


6

Kotlinではさまざまな方法で実行できます

  1. ifを使用する

    if(a) b else c
  2. いつ使用する

    when (a) { 
        true -> print("value b") 
        false -> print("value c") 
        else -> {  
            print("default return in any other case") 
        } 
    }
  3. ヌルセーフティ

    val a = b ?: c

5

Kotlinには3項演算はありませんが、これを回避する楽しい方法がいくつかあります。他の人が指摘したように、Kotlinへの直接翻訳は次のようになります。

val x = if (condition) result1 else result2

しかし、個人的には、少し雑然として読みにくくなると思います。ライブラリには他にもいくつかのオプションが組み込まれています。elvis演算子でtakeIf {}を使用できます。

val x = result1.takeIf { condition } ?: result2

ここで何が起こっているのかというと、takeIf {}コマンドがresult1またはnullを返し、elvisオペレーターがnullオプションを処理します。いくつかの追加オプションがあります。たとえば、takeUnless {}です。

val x = result1.takeUnless { condition } ?: result2

言語は明確です、あなたはそれが何をしているのか知っています。

それが一般的に使用される条件である場合、インライン拡張メソッドを使用するような楽しいこともできます。たとえば、ゲームのスコアをIntとして追跡し、特定の条件が満たされない場合は常に0を返したいとしましょう。

inline fun Int.zeroIfFalse(func: () -> Boolean) : Int = if (!func.invoke()) 0 else this     

OK、それは醜いようです。ただし、使用時の外観を考慮してください。

var score = 0
val twoPointer = 2
val threePointer = 3

score += twoPointer.zeroIfFalse { scoreCondition } 
score += threePointer.zeroIfFalse { scoreCondition } 

ご覧のとおり、Kotlinはコードの表現方法を柔軟に選択できます。私の例には無数のバリエーションがあり、おそらく私がまだ発見していない方法もあります。これが役に立てば幸いです!


takeIf本当に私のお気に入りのオプションです。とてもエレガントです。
JavierMendonça18年

4

Ternary演算子Elvis演算子は、多くの一般的な言語とは異なり、Kotlinでは異なる意味を持っていることを覚えておいてください。こうexpression? value1: value2することによって、あなたに悪い言葉を与えるだろうKotlinのがないので、他の言語とは異なり、コンパイラKotlinには三項演算子で述べたように公式ドキュメントが。その理由は、if、when、try-catchステートメント自体が値を返すためです。

だから、実行expression? value1: value2することで置き換えることができます

val max = if(a> b)print( "Choose a")else print( "Choose b")

エルビス演算子というKotlinが持っているが、唯一のNULL可能変数EXの場合に動作します:

私がそのようなことvalue3 = value1 ?: value2をした場合、value1nullの場合はvalue2が返され、それ以外の場合はvalue1が返されます。

これらの回答からより明確な理解を得ることができます


3

使用できます ifKotlinではこの式を。Kotlinではif、結果値を持つ式です。Kotlinでは次のように書くことができます

fun max(a: Int, b: Int) = if (a > b) a else b

そしてJavaでは同じことを達成できますが、より大きなコードで

int max(int a, int b) {
return a > b ? a : b
}

2

標準表記を使用しない場合は、infixを使用して作成/シミュレーションすることもできます。、次のようなを。

ターゲットと結果を保持するクラスを作成します。

data class Ternary<T>(val target: T, val result: Boolean)

三項演算をシミュレートするいくつかのインフィックス関数を作成する

infix fun <T> Boolean.then(target: T): Ternary<T> {
    return Ternary(target, this)
}

infix fun <T> Ternary<T>.or(target: T): T {
    return if (this.result) this.target else target
}

その後、次のように使用できます。

val collection: List<Int> = mutableListOf(1, 2, 3, 4)

var exampleOne = collection.isEmpty() then "yes" or "no"
var exampleTwo = (collection.isNotEmpty() && collection.contains(2)) then "yes" or "no"
var exampleThree = collection.contains(1) then "yes" or "no"

実際の三項演算子と完全に同等にするために、ターゲット値はTを提供するラムダにすることもできます
アランの老人


1

なぜこのようなものを使用するのですか?

when(a) {
  true -> b
  false -> b
}

あなたが実際にこのようなものを使用できるとき(aこの場合はブール値です):

when {
  a -> b
  else -> b
}

1
最初のものは意味的に明確で、Kotlinに精通していなくても、他の誰かがそれを読んでいる人には簡単に理解できるので、2番目のものはそうではありません。
mc01 2018

1
さて、あなたは要点を理解しましたが、Kotlin開発者が三項式を導入しなかった理由を理解できません
ZZ 5

? and :型チェックではなく、nullable /型宣言と矛盾すると思います。それ以外は何の理由もありません。インラインif-else条件チェックがあれば、誰かが間違いなくいくつかのことを考えたでしょう。待って、将来のバージョンで見てみましょう。
bh4r4th

1

apply()を使用する場合は、3項演算を処理するときに非常に便利です。これは、エレガントでスペースが確保されるためです。

val columns: List<String> = ...
val band = Band().apply {
    name = columns[0]
    album = columns[1]
    year = columns[2].takeIf { it.isNotEmpty() }?.let { it.toInt() } ?: 0
}

0

次のインフィックス関数を使用すると、Pythonで実行できるのとほとんど同じ方法で、多くの一般的な使用例をカバーできます。

class TestKotlinTernaryConditionalOperator {

    @Test
    fun testAndOrInfixFunctions() {
        Assertions.assertThat(true and "yes" or "no").isEqualTo("yes")
        Assertions.assertThat(false and "yes" or "no").isEqualTo("no")

        Assertions.assertThat("A" and "yes" or "no").isEqualTo("yes")
        Assertions.assertThat("" and "yes" or "no").isEqualTo("no")

        Assertions.assertThat(1 and "yes" or "no").isEqualTo("yes")
        Assertions.assertThat(0 and "yes" or "no").isEqualTo("no")

        Assertions.assertThat(Date() and "yes" or "no").isEqualTo("yes")
        @Suppress("CAST_NEVER_SUCCEEDS")
        Assertions.assertThat(null as Date? and "yes" or "no").isEqualTo("no")
    }
}

infix fun <E> Boolean?.and(other: E?): E? = if (this == true) other else null
infix fun <E> CharSequence?.and(other: E?): E? = if (!(this ?: "").isEmpty()) other else null
infix fun <E> Number?.and(other: E?): E? = if (this?.toInt() ?: 0 != 0) other else null
infix fun <E> Any?.and(other: E?): E? = if (this != null) other else null
infix fun <E> E?.or(other: E?): E? = this ?: other

0

Kotlinには三項演算子はありません。最も閉じているのは、以下の2つのケースです。

  • それ以外の場合は式ステートメント

val a = true if(a) print("A is true") else print("A is false")

  • Elvisオペレーター

?:の左側の式がnullでない場合、elvis演算子はそれを返します。それ以外の場合は、右側の式を返します。右側の式は、左側がnullの場合にのみ評価されることに注意してください。

 val name = node.getName() ?: throw IllegalArgumentException("name expected")

リファレンスドキュメント


0

例: var energy:Int = data?.get(position)?. energy?.toInt()?:0

kotlinでは、?:を使用して いる場合は、ステートメントがnullを返した場合と同じように機能し、 ?:0は、0またはこの側で書き込んだものを受け取ります。


-1

Kotlinでは、次のような3項演算を使用できます。 val x = if(a) "add b" else "add c"


1
この質問はすでに十分に回答されており、最近更新されていません。以前の回答と変わらない別の回答を今すぐ投稿する必要はありません。
ヘッドクラッカー

-2

他のアイデアを調査した後、次の3項演算子を導出しました。

infix fun <T : Any> Boolean.yes(trueValue: T): T? = if (this) trueValue else null
infix fun <T : Any> T?.no(falseValue: T): T = this ?: falseValue

例(ここで実行):

fun main() {
    run {
        val cond = true
        val result = cond yes "True!" no "False!"
        println("ternary test($cond): $result")
    }
    run {
        val cond = false
        val result = cond yes "True!" no "False!"
        println("ternary test($cond): $result")
    }
}

このバージョンは流暢であり、nullの合体演算子と競合しません。


これは、のthen代わりに名前が付けられている逸脱者の回答と同じですyes
Ry-

@Ryはい、そして彼らが同じ人物かどうかはわかりませんが、オプションでinfixメソッドを使用するという考えはKotlinフォーラムから来ています。ほとんどの言語のように、疑問符が条件の代わりに「then値」の後ろにあるため、null結合演算子のインライン使用が混乱するため、私が思いついた「no」メソッドは見たことがない。
ブライアンW.ワーグナー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.