Operator Bersyarat Kotlin Ternary

Jawaban:

618

Di Kotlin, ifpernyataan adalah ekspresi. Jadi kode berikut ini setara:

if (a) b else c

Perbedaan antara ekspresi dan pernyataan adalah penting di sini. Dalam Java / C # / JavaScript, ifbentuk pernyataan, yang berarti bahwa itu tidak menentukan nilai. Lebih konkretnya, Anda tidak dapat menetapkannya ke variabel.

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

Jika Anda berasal dari bahasa di mana ifpernyataan, ini mungkin tampak tidak wajar tetapi perasaan itu harus segera mereda.

Drew Noakes
sumber
57
Selain itu Anda dapat menggunakan when.
bashor
5
hanya untuk menambahkan, jika itu adalah ekspresi boolean, Anda bahkan dapat pergi denganx = a==b
gnomeria
2
@ MikeRylander Saya telah memperluas jawaban untuk membuat ini eksplisit. Terima kasih telah menunjukkan ini.
Drew Noakes
1
@AdeelAnsari Tidak, ini tidak meluruskan. Itu lebih buruk. Bandingkan ini. b + if (a) c else dvs. b + (c if (a) else d)Yang terakhir membutuhkan kurung tambahan. karena ctidak tertutup oleh kondisi dan else.
Naetmul
1
Inilah sedikit diskusi tentang topik ini. mendiskusikan.kotlinlang.org/t/ternary-operator/2116/141
F. Norbert
70

Anda dapat menentukan Booleanfungsi ekstensi Anda sendiri yang kembali nullketika Booleanadalah falseuntuk menyediakan struktur yang mirip dengan operator ternary:

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

Ini akan membuat a ? b : cekspresi diterjemahkan menjadi a then b ?: c, seperti:

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

Pembaruan: Tetapi untuk melakukan beberapa saklar kondisional seperti Java, Anda akan memerlukan sesuatu seperti itu

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

println(condition then { "yes" } ?: "no") perhatikan lambda. Perhitungan isinya harus ditunda sampai kami pastikan conditionadalahtrue

Yang ini terlihat kikuk, itu sebabnya ada permintaan yang tinggi ada untuk operator pelabuhan ternary Jawa ke Kotlin

menyimpang
sumber
1
infix inline fun<T> Boolean.then(param: ()->T):T? = if(this) param() else null
nullbyte
3
Gunakan <T: Any>, jika tidak maka itu tidak akan berfungsi dengan baik:true then { null } ?: "not-null"
Eugene Petrenko
BTW, ?:operator di sini adalah elvis-operator: kotlinlang.org/docs/reference/null-safety.html#elvis-operator
Eric Wang
64

TL; DR

if (a) b else c

adalah apa yang dapat Anda gunakan sebagai ganti ekspresi operator ternary a ? b : c.


Di Kotlin, banyak pernyataan kontrol termasuk if, whenatau bahkan trydapat digunakan sebagai ekspresi . Ini berarti bahwa mereka dapat memiliki hasil yang dapat ditetapkan ke variabel, dikembalikan dari fungsi dll.

Secara sintaksis, tidak perlu operator ternary

Sebagai hasil dari ekspresi Kotlin, bahasa tidak benar-benar membutuhkan operator ternary .

if (a) b else c

adalah apa yang dapat Anda gunakan sebagai ganti ekspresi operator ternary a ? b : c.

Saya pikir idenya adalah bahwa ekspresi sebelumnya lebih mudah dibaca karena semua orang tahu apa yang ifelsedilakukan, sedangkan ? :agak tidak jelas jika Anda belum terbiasa dengan sintaks.

Meskipun demikian, saya harus mengakui bahwa saya sering kehilangan operator ternary yang lebih nyaman.


Alternatif Lainnya

kapan

Anda mungkin juga melihat whenkonstruksi yang digunakan di Kotlin ketika kondisinya diperiksa. Ini juga cara untuk mengungkapkan jika-cascade dengan cara alternatif. Berikut ini sesuai dengan contoh PL.

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

Ekstensi

Seperti banyak contoh yang baik ( Operator Bersyarat Kotlin Ternary ) dalam jawaban lain menunjukkan, ekstensi juga dapat membantu memecahkan kasus penggunaan Anda.

s1m0nw1
sumber
36

Untuk saya sendiri saya menggunakan fungsi ekstensi berikut:

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

Pertama akan mengembalikan asalkan nilai default dalam kasus objek sama dengan nol. Kedua akan mengevaluasi ekspresi yang disediakan dalam lambda dalam kasus yang sama.

Pemakaian:

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

Secara pribadi bagi saya kode di atas lebih mudah dibaca daripada ifinlining konstruksi

ruX
sumber
34
Ini tidak relevan dengan pertanyaan, tetapi mengapa tidak digunakan ?: , Operator elvis ? Fungsi pertama akan diganti dengan e.getMessage() ?: "unknown". Yang kedua dapat dinyatakan sebagaiobj?.lastMessage?.timestamp ?: { Date() }()
hotkey
1
@ hotkey tidak ada tujuan khusus untuk itu. Dari sudut pandang saya, ini terlihat lebih konsisten dan secara visual tidak terlalu berisik dalam operasi rantai karena Anda tidak boleh membungkus konstruksi dalam tanda kurung
ruX
14
@ruX operator elvis khusus untuk ini dan penggunaan Anda agak tidak biasa.
Jayson Minard
6
Sementara?: Baik-baik saja, jangan pergi terlalu jauh ke Perl.
Richard Haven
28

Tidak ada operator ternary di kotlin, karena if elseblok mengembalikan nilai

jadi, Anda bisa melakukan: val max = if (a > b) a else b alih-alih javamax = (a > b) ? b : c

Kami juga dapat menggunakan whenkonstruksi, juga mengembalikan nilai:

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

Berikut ini tautan untuk dokumentasi kotlin: Aliran Kontrol: if, when, for, while

romiope
sumber
27

Di Kotlin, ifadalah ekspresi, yaitu mengembalikan nilai. Oleh karena itu tidak ada operator ternary (condition ? then : else), karena biasa jika berfungsi dengan baik dalam peran ini. sumber manual dari sini

// 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
Kris Roofe
sumber
26

Beberapa kasus sudut tidak disebutkan dalam jawaban lain.

Sejak kemunculan takeIf di Kotlin 1.1 , operator ternary a ? b : cjuga dapat diekspresikan seperti ini:

b.takeIf { a } ?: c

Ini menjadi lebih pendek jika c adalah null:

b.takeIf { a }

Juga catat bahwa tipikal di dunia Java nol cek seperti value != null ? value : defaultValuemenerjemahkan dalam Kotlin ideomatis menjadi adil value ?: defaultValue.

Serupa a != null ? b : cdapat diterjemahkan ke a?.let { b } ?: c.

Vadzim
sumber
6
Bagaimana b.takeIf { a } ?: clebih pendek dan lebih mudah dibaca daripada if (a) b else c? Operator Terneray tentu saja merupakan fitur yang hilang di Kotlin karena nama variabel dan kondisinya dapat panjang dan membuat Anda membagi garis yang buruk
Javad Sadeqzadeh
1
Perlu juga dicatat bahwa takeIfselalu mengevaluasi kasus sebenarnya (di sini a). Tidak hanya ekspresi itu dapat dihitung secara sia-sia jika akebetulan salah, tetapi Anda tidak bisa mendapatkan manfaat dari gips cerdas à la if (a is Int) { a + 3 }.
TheOperator
@TheOperator, salah. { a }adalah lambda yang dievaluasi dengan malas.
Vadzim
1
Saya menulisnya salah, harus "selalu mengevaluasi kasus yang sebenarnya (di sini b)". Tetapi meski { a }malas, harus dievaluasi untuk menentukan hasil ekspresi.
TheOperator
24

Lihatlah dokumen :

Di Kotlin, if adalah ekspresi, artinya mengembalikan nilai. Oleh karena itu tidak ada operator ternary (kondisi? Lalu: lain), karena biasa jika berfungsi dengan baik dalam peran ini.

Li Ying
sumber
13

Jawa

int temp = a ? b : c;

Setara dengan Kotlin :

var temp = if (a) b else c
dua kali lipat
sumber
12

TUGAS :

Mari kita perhatikan contoh berikut:

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

Kami membutuhkan yang setara di Kotlin berikut:

return (! answer.isSuccessful ()) ? "salah" : answer.body (). string ()


SOLUSI :

1.a . Anda dapat menggunakan if-expressiondi Kotlin:

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

1.b . Akan jauh lebih baik jika Anda membalik ini if-expression(mari kita lakukan tanpa not):

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

2 . Operator Kotlin's Elvis ?:dapat melakukan pekerjaan dengan lebih baik:

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

3 . Atau gunakan Extension functionuntuk Answerkelas yang sesuai :

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

4 . Menggunakan Extension functionAnda dapat mengurangi kode berkat Elvis operator:

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

5 . Atau cukup gunakan whenoperator:

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

Semoga ini membantu.

Andy
sumber
11

saat mengganti operator sakelar dari bahasa yang mirip C. Dalam bentuk yang paling sederhana terlihat seperti ini

when (x) {
    1 -> print("x == 1")
    2 -> print("x == 2")
    else -> {
        print("x is neither 1 nor 2")
    }
}
Guruprasath
sumber
3
Benar, tetapi contoh yang Anda tampilkan memiliki whensebagai pernyataan, bukan ekspresi. Perbandingan yang lebih relevan dengan ekspresi kondisional terner adalah memiliki setiap cabang mengembalikan nilai, sehingga keseluruhan ketika ekspresi mengevaluasi ke nilai (seperti yang terjadi dengan kondisional terner).
Drew Noakes
9

Tidak ada operator ternary di Kotlin. Tampaknya bermasalah pada pandangan pertama. Tetapi berpikir kita bisa melakukannya dengan pernyataan inline if else karena ini adalah ekspresi di sini. Yang harus kita lakukan -

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

Di sini kita dapat lagi jika memblokir terlalu banyak yang kita butuhkan. Suka-

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

Jadi saluran ini sangat sederhana dan lebih mudah dibaca daripada operator ternary. ketika kita menggunakan lebih dari satu operator ternary di java sepertinya mengerikan. Tetapi di sini kita memiliki sintaks yang jelas. bahkan kita bisa menulisnya dalam banyak baris juga.

HM Nayem
sumber
9

Anda dapat menggunakannya var a= if (a) b else csebagai pengganti operator ternary.

Konsep lain yang baik dari kotlin adalah operator Elvis. Anda tidak perlu memeriksa nol setiap saat.

val l = b?.length ?: -1

Ini akan mengembalikan panjang jika b bukan nol jika tidak dieksekusi pernyataan sisi kanan.

Android Geek
sumber
7

seperti dikutip Drew Noakes, kotlin menggunakan jika pernyataan sebagai ekspresi, sehingga Operator Bersyarat tidak diperlukan lagi,

tetapi dengan fungsi ekstensi dan infix overloading, Anda bisa menerapkannya sendiri, berikut ini contohnya

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
}

lalu gunakan seperti ini

val grade = 90
val clazz = (grade > 80) then "A" or "B"
Minami
sumber
Mungkin menghapus <T> lebih baik? infix fun atau (falsy: T?) = If (flag) benar-benar lain falsy
solo
1
Tetapi menambahkan <T> dapat membuatnya bekerja: (kelas> 80) lalu nol atau "B"
solo
Ini sangat keren, saya akan menggunakannya: P Tetapi perlu dicatat bahwa, kecuali saya salah, itu akan menyebabkan alokasi objek setiap kali dipanggil. Bukan masalah besar, tetapi perlu diketahui itu bukan abstraksi nol biaya.
Adam
6

Pendekatan lain yang menarik adalah menggunakan when:

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

Dapat sangat berguna dalam beberapa skenario yang lebih kompleks. Dan jujur, itu lebih mudah dibaca daripada bagi sayaif ... else ...

Grzegorz Piwowarek
sumber
6

Anda dapat melakukannya dengan berbagai cara di Kotlin

  1. Menggunakan if

    if(a) b else c
  2. Menggunakan kapan

    when (a) { 
        true -> print("value b") 
        false -> print("value c") 
        else -> {  
            print("default return in any other case") 
        } 
    }
  3. Keamanan Null

    val a = b ?: c
Rajesh Dalsaniya
sumber
5

Tidak ada operasi ternary di Kotlin, tetapi ada beberapa cara yang menyenangkan untuk mengatasinya. Seperti yang telah ditunjukkan orang lain, terjemahan langsung ke Kotlin akan terlihat seperti ini:

val x = if (condition) result1 else result2

Tapi, secara pribadi, saya pikir itu bisa sedikit berantakan dan sulit dibaca. Ada beberapa opsi lain yang dibangun ke perpustakaan. Anda dapat menggunakan takeIf {} dengan operator elvis:

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

Apa yang terjadi di sana adalah bahwa perintah takeIf {} mengembalikan result1 atau null Anda, dan operator elvis menangani opsi nol. Ada beberapa opsi tambahan, takeUnless {}, misalnya:

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

Bahasanya jelas, Anda tahu apa yang dilakukannya.

Jika ini adalah kondisi yang umum digunakan, Anda juga dapat melakukan sesuatu yang menyenangkan seperti menggunakan metode ekstensi sebaris. Misalnya, kita ingin melacak skor game sebagai Int, dan kami ingin selalu mengembalikan 0 jika kondisi yang diberikan tidak terpenuhi:

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

Ok, sepertinya jelek. Tetapi pertimbangkan bagaimana tampilannya ketika digunakan:

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

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

Seperti yang Anda lihat, Kotlin menawarkan banyak fleksibilitas dalam cara Anda memilih untuk mengekspresikan kode Anda. Ada banyak variasi contoh saya dan mungkin cara yang belum saya temukan. Saya harap ini membantu!

pranalli
sumber
takeIfmemang pilihan favorit saya, sangat elegan.
Javier Mendonça
4

Ingat operator ternary dan operator Elvis memiliki makna yang berbeda di Kotlin tidak seperti dalam banyak bahasa populer. Melakukan expression? value1: value2akan memberi Anda kata-kata buruk oleh kompiler Kotlin , tidak seperti bahasa lain karena tidak ada operator ternary di Kotlin seperti yang disebutkan dalam dokumen resmi . Alasannya adalah bahwa pernyataan if, when dan try-catch sendiri mengembalikan nilai.

Jadi, melakukan expression? value1: value2bisa diganti dengan

val max = jika (a> b) cetak ("Pilih a") cetak lain ("Pilih b")

The Elvis Operator yang Kotlin memiliki, bekerja hanya dalam kasus variabel nullable ex .:

Jika saya melakukan sesuatu seperti value3 = value1 ?: value2maka jika value1 adalah null maka value2 akan dikembalikan sebaliknya value1 akan dikembalikan.

Pemahaman yang lebih jelas dapat dicapai dari jawaban-jawaban ini .

Neeraj Sewani
sumber
3

Anda dapat menggunakan ifekspresi untuk ini di Kotlin. Di Kotlin ifadalah ekspresi dengan nilai hasil. Jadi di Kotlin kita bisa menulis

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

dan di Jawa kita dapat mencapai hal yang sama tetapi dengan kode yang lebih besar

int max(int a, int b) {
return a > b ? a : b
}
Gulzar Bhat
sumber
2

Jika Anda tidak ingin menggunakan notasi standar, Anda juga dapat membuat / mensimulasikannya menggunakan infix dengan sesuatu seperti ini:

buat kelas untuk menampung target dan hasil Anda:

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

buat beberapa fungsi infiks untuk mensimulasikan operasi ternary

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
}

Maka Anda akan dapat menggunakannya seperti ini:

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"
Eudy Contreras
sumber
Untuk membuatnya benar-benar setara dengan operator ternary yang sebenarnya, nilai target juga dapat menjadi lambda memasok T
Old Man of Aran
1

Pendekatan pendek lain untuk digunakan

val value : String = "Kotlin"

value ?: ""

Di sini kotlin sendiri memeriksa nilai nol dan jika itu nol maka ia melewati nilai string kosong.

Vinod Pattanshetti
sumber
1

Mengapa orang menggunakan sesuatu seperti ini:

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

ketika Anda benar-benar dapat menggunakan sesuatu seperti ini ( adalam hal ini adalah boolean):

when {
  a -> b
  else -> b
}
ZZ 5
sumber
1
Karena yang pertama jelas secara semantik & mudah dimengerti oleh orang lain yang membacanya walaupun mereka tidak terbiasa dengan Kotlin, sedangkan yang kedua tidak.
mc01
1
Yah, Anda sudah mengerti, tetapi saya tidak bisa mengerti mengapa pengembang Kotlin tidak memperkenalkan ekspresi ternary
ZZ 5
Saya pikir ? and :bertentangan dengan deklarasi nullable / type daripada jenis cek. Selain itu, saya tidak melihat alasan. Saya pikir seseorang pasti akan mempertimbangkan, jika ada inline if-else memeriksa kondisi. Mari kita tunggu dan lihat di versi mendatang.
Bh4r4th
1

Ketika bekerja dengan apply (), biarkan terasa sangat berguna ketika berhadapan dengan operasi ternary, karena lebih elegan dan memberi Anda ruang

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

Dengan fungsi infix berikut, saya dapat membahas banyak kasus penggunaan umum dengan cara yang hampir sama dengan yang dapat dilakukan dengan 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
Nicolas Cornette
sumber
0

Tidak ada operator ternary di Kotlin, yang paling tertutup adalah di bawah dua kasus,

  • Jika lain sebagai pernyataan ekspresi

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

  • Operator Elvis

Jika ekspresi di sebelah kiri?: Bukan nol, operator elvis mengembalikannya, jika tidak, mengembalikan ekspresi ke kanan. Perhatikan bahwa ekspresi sisi kanan dievaluasi hanya jika sisi kiri adalah nol.

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

Dokumen referensi

JTeam
sumber
0

contoh: var energy: Int = data? .get (posisi) ?. energy? .toInt ()?: 0

Dalam Kotlin jika Anda menggunakan :? Itu akan bekerja seperti jika pernyataan itu akan kembali null maka :? 0 akan mengambil 0 atau apa pun yang Anda harus menulis sisi ini.

abhilasha Yadav
sumber
-1

Di Kotlin Anda dapat menggunakan operasi ternary seperti ini: val x = if(a) "add b" else "add c"

manuelernest0
sumber
1
Pertanyaan ini sudah dijawab sudah cukup, dan belum diperbarui baru-baru ini. Tidak perlu memposting sekarang jawaban lain yang tidak berbeda dari yang sebelumnya.
Headcracker
-2

Setelah melakukan riset terhadap ide-ide lain, saya telah menurunkan operator ternary berikut:

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

Contoh (jalankan di sini ):

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")
    }
}

Versi ini lancar dan tidak bertentangan dengan operator penggabungan nol.

Bryan W. Wagner
sumber
Ini agak sama dengan jawaban menyimpang di mana namanya thenbukan yes.
Ry-
@Ry ya, dan saya tidak yakin apakah mereka orang yang sama tetapi gagasan untuk menggunakan metode infiks dengan opsional berasal dari forum Kotlin. Apa yang belum saya lihat adalah metode 'tidak' yang saya buat karena saya menemukan inline penggunaan operator penggabungan nol membingungkan karena tanda tanya adalah setelah 'nilai kemudian' daripada kondisi seperti itu dalam kebanyakan bahasa.
Bryan W. Wagner