Operatore condizionale ternario di Kotlin


Risposte:


619

In Kotlin, le ifdichiarazioni sono espressioni. Quindi il seguente codice è equivalente:

if (a) b else c

La distinzione tra espressione e affermazione è importante qui. In Java / C # / JavaScript, ifforma un'istruzione, il che significa che non si risolve in un valore. Più concretamente, non è possibile assegnarlo a una variabile.

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

Se provieni da una lingua in cui ifè presente un'affermazione, questo potrebbe sembrare innaturale, ma questa sensazione dovrebbe presto placarsi.


57
Inoltre puoi usare when.
bashor

5
solo per aggiungere, se è un'espressione booleana, puoi persino andare conx = a==b
gnomeria

2
@MikeRylander Ho esteso la risposta per renderlo esplicito. Grazie per averlo segnalato.
Drew Noakes,

1
@AdeelAnsari No, non sta rettificando. È peggio. Confronta questo. b + if (a) c else dvs. b + (c if (a) else d)Quest'ultimo richiede parentesi aggiuntive. perché cnon è racchiuso dalla condizione e else.
Naetmul,

1
Ecco una piccola discussione su questo argomento. discuss.kotlinlang.org/t/ternary-operator/2116/141
F. Norbert,

70

È possibile definire la propria Booleanfunzione di estensione che ritorna nullquando Booleandeve falsefornire una struttura simile all'operatore ternario:

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

Ciò farebbe a ? b : ctradurre un'espressione in questo a then b ?: cmodo:

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

Aggiornamento: ma per fare un po 'più di interruttore condizionale simile a Java avrai bisogno di qualcosa del genere

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

println(condition then { "yes" } ?: "no") presta attenzione alla lambda. il calcolo contenuto dovrebbe essere rimandata fino a quando ci assicuriamo che conditionètrue

Questo sembra goffo, ecco perché esiste una richiesta molto richiesta per il porting dell'operatore ternario Java in Kotlin


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

3
Usa <T: Qualsiasi>, altrimenti funzionerà in modo errato:true then { null } ?: "not-null"
Eugene Petrenko,

A proposito, l' ?:operatore qui è elvis-operator: kotlinlang.org/docs/reference/null-safety.html#elvis-operator
Eric Wang

64

TL; DR

if (a) b else c

è quello che puoi usare invece dell'espressione dell'operatore ternario a ? b : c.


In Kotlin, molte espressioni di controllo incluse if, wheno persino trypossono essere usate come espressioni . Ciò significa che quelli possono avere un risultato che può essere assegnato a una variabile, restituito da una funzione ecc.

Sintatticamente, non è necessario un operatore ternario

Come risultato delle espressioni di Kotlin, la lingua non ha davvero bisogno dell'operatore ternario .

if (a) b else c

è quello che puoi usare invece dell'espressione dell'operatore ternario a ? b : c.

Penso che l'idea sia che l'espressione precedente sia più leggibile poiché tutti sanno cosa ifelsefa, mentre non ? :è abbastanza chiaro se non si ha già familiarità con la sintassi.

Tuttavia, devo ammettere che spesso mi manca l'operatore ternario più conveniente.


Altre alternative

quando

Potresti anche vedere whencostrutti usati in Kotlin quando le condizioni sono controllate. È anche un modo per esprimere le cascate if-else in modo alternativo. Quanto segue corrisponde all'esempio di OT.

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

estensioni

Come molti buoni esempi ( Operatore condizionale ternario di Kotlin ) nelle altre risposte mostrano, le estensioni possono anche aiutare a risolvere il tuo caso d'uso.


36

Per quanto mi riguarda, utilizzo le seguenti funzioni di estensione:

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

Il primo restituirà il valore predefinito fornito nel caso in cui l'oggetto sia uguale a null. Il secondo valuterà l'espressione fornita in lambda nello stesso caso.

Uso:

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

Personalmente per me il codice sopra è più leggibile rispetto al ifrivestimento interno


34
Non è così rilevante per la domanda, ma perché non usare ?: , L' operatore elvis ? La prima funzione verrebbe sostituita con e.getMessage() ?: "unknown". Il secondo può essere espresso comeobj?.lastMessage?.timestamp ?: { Date() }()
tasto di scelta rapida

1
@hotkey non ha uno scopo speciale per questo. Dal mio punto di vista sembra più coerente e visivamente meno rumoroso nelle operazioni a catena in quanto non dovresti avvolgere la costruzione tra parentesi
ruX

14
@ruX l'operatore elvis è specifico per questo e il tuo utilizzo è piuttosto insolito.
Jayson Minard,

6
Mentre?: Va bene, non andare troppo lontano lungo la strada per Perl.
Richard Haven,


28

Non esiste alcun operatore ternario in kotlin, poiché il if elseblocco restituisce valore

quindi, puoi fare: val max = if (a > b) a else b invece di javamax = (a > b) ? b : c

Possiamo anche usare la whencostruzione, che restituisce anche valore:

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

Ecco il link per la documentazione di kotlin: Flusso di controllo: if, when, for, while


27

In Kotlin, ifè un'espressione, ovvero restituisce un valore. Pertanto non esiste un operatore ternario (condition ? then : else), perché ordinario se funziona bene in questo ruolo. fonte manuale da qui

// 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

Alcuni casi d'angolo non menzionati in altre risposte.

Dall'apparizione di takeIf in Kotlin 1.1 l'operatore ternario a ? b : cpuò anche essere espresso in questo modo:

b.takeIf { a } ?: c

Questo diventa ancora più breve nel caso in cui c sia null:

b.takeIf { a }

Nota anche che nel mondo Java i controlli null come value != null ? value : defaultValuetraducono in ideologico Kotlin in giusto value ?: defaultValue.

Simile a != null ? b : cpuò essere tradotto in a?.let { b } ?: c.


6
Quanto è b.takeIf { a } ?: cpiù breve e più leggibile di if (a) b else c? L'operatore di Terneray è certamente una caratteristica mancante in Kotlin poiché i nomi delle variabili e la condizione possono essere lunghi e farti dividere la linea che è male
Javad Sadeqzadeh

1
Va anche notato che takeIfvaluta sempre il caso vero (qui a). Non solo quell'espressione può essere calcolata inutilmente se asembra essere falsa, ma non puoi beneficiare di cast intelligenti if (a is Int) { a + 3 }.
TheOperator,

@TheOperator, sbagliato. { a }è una lambda pigramente valutata.
Vadzim,

1
L'ho scritto male, dovrebbe essere "valuta sempre il caso vero (qui b)". Ma anche { a }, sebbene pigro, deve essere valutato per determinare il risultato dell'espressione.
TheOperator

24

Dai un'occhiata ai documenti :

In Kotlin, if è un'espressione, ovvero restituisce un valore. Pertanto non esiste un operatore ternario (condizione? Allora: altro), perché ordinario se funziona bene in questo ruolo.


13

Giava

int temp = a ? b : c;

Equivalente a Kotlin :

var temp = if (a) b else c

12

COMPITO :

Consideriamo il seguente esempio:

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

Abbiamo bisogno del seguente equivalente in Kotlin:

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


SOLUZIONI :

1.a . Puoi usare if-expressionin Kotlin:

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

1.B . Può essere molto meglio se capovolgi questo if-expression(facciamolo senza not):

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

2 . L'operatore Elvis di Kotlin ?:può fare un lavoro ancora meglio:

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

3 . Oppure usa un Extension functionper la Answerclasse corrispondente :

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

4 . Usando Extension functionè possibile ridurre un codice grazie a Elvis operator:

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

5 . O semplicemente usa l' whenoperatore:

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

Spero che sia di aiuto.


11

quando sostituisce l'operatore switch di linguaggi di tipo C. Nella forma più semplice sembra così

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

3
Vero, ma l'esempio che mostri ha whencome un'istruzione, non un'espressione. Un confronto più pertinente con le espressioni condizionali ternarie sarebbe di fare in modo che ciascun ramo restituisca un valore, in modo tale che l'intera espressione quando valuti un valore (come accade con i condizionali ternari).
Drew Noakes

9

Non esiste un operatore ternario a Kotlin. Sembra problematico a prima vista. Ma pensa che possiamo farlo con un'istruzione if else inline perché questa è espressione qui. Semplicemente dobbiamo fare -

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

Qui possiamo altro se bloccare troppi quanti ne abbiamo bisogno. Piace-

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

Quindi questa linea è così semplice e molto leggibile rispetto all'operatore ternario. quando usiamo più di un operatore ternario in Java sembra orribile. Ma qui abbiamo una sintassi chiara. anche noi possiamo scriverlo anche su più righe.


9

È possibile utilizzare var a= if (a) b else cal posto dell'operatore ternario.

Un altro buon concetto di kotlin è l'operatore Elvis. Non è necessario controllare null ogni volta.

val l = b?.length ?: -1

Questo restituirà la lunghezza se b non è null, altrimenti esegue l'istruzione sul lato destro.


7

come citato da Drew Noakes, kotlin usa if come espressione, quindi Ternary Conditional Operator non è più necessario,

ma con la funzione di estensione e il sovraccarico infisso, potresti implementarlo da solo, ecco un esempio

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
}

quindi usalo in questo modo

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

Forse rimuovi <T> meglio? infondi divertimento o (falsy: T?) = If (flag) davvero altro falsy
solo

1
Ma aggiungi <T> può farlo funzionare: (grado> 80) quindi null o "B"
solo

Questo è davvero bello, lo userò: P Ma nota che, a meno che non mi sbagli, causerà un'allocazione degli oggetti ogni volta che viene chiamato. Non è un grosso problema, ma vale la pena sapere che non è un'astrazione a costo zero.
Adam,

6

Un altro approccio interessante sarebbe quello di utilizzare when:

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

Può essere abbastanza utile in alcuni scenari più complessi. E onestamente, è più leggibile per me cheif ... else ...


6

Puoi farlo in molti modi a Kotlin

  1. Usando if

    if(a) b else c
  2. Usando quando

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

    val a = b ?: c

5

Non esiste un'operazione ternaria a Kotlin, ma ci sono alcuni modi divertenti per aggirare questo. Come altri hanno sottolineato, una traduzione diretta in Kotlin sarebbe simile a questa:

val x = if (condition) result1 else result2

Ma, personalmente, penso che possa essere un po 'ingombra e difficile da leggere. Ci sono alcune altre opzioni integrate nella libreria. Puoi usare takeIf {} con un operatore elvis:

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

Quello che sta succedendo lì è che il comando takeIf {} restituisce il risultato1 o null e l'operatore elvis gestisce l'opzione null. Ci sono alcune opzioni aggiuntive, takeUnless {}, ad esempio:

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

La lingua è chiara, sai cosa sta facendo.

Se è una condizione comunemente usata, potresti anche fare qualcosa di divertente come usare un metodo di estensione in linea. Supponiamo di voler monitorare un punteggio di gioco come Int, ad esempio, e vogliamo sempre restituire 0 se una determinata condizione non è soddisfatta:

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

Ok, sembra brutto. Ma considera come appare quando viene utilizzato:

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

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

Come puoi vedere, Kotlin offre molta flessibilità nel modo in cui scegli di esprimere il tuo codice. Ci sono innumerevoli varianti dei miei esempi e probabilmente modi che non ho ancora scoperto. Spero che questo possa essere d'aiuto!


takeIfè davvero la mia opzione preferita, molto elegante.
Javier Mendonça,

4

Ricorda che l' operatore ternario e l' operatore Elvis hanno significati separati in Kotlin, a differenza di molte lingue popolari. Fare expression? value1: value2ti darebbe parolacce dal compilatore di Kotlin , a differenza di qualsiasi altra lingua in quanto non esiste un operatore ternario a Kotlin come menzionato nei documenti ufficiali . Il motivo è che le stesse istruzioni if, when e try-catch restituiscono valori.

Quindi, fare expression? value1: value2può essere sostituito da

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

L' operatore Elvis che Kotlin ha, funziona solo nel caso di variabili nullable es .:

Se faccio qualcosa del genere, value3 = value1 ?: value2allora se value1 è null allora value2 verrebbe restituito altrimenti value1 verrebbe restituito.

Una comprensione più chiara può essere raggiunta da queste risposte .


3

Puoi usare l' ifespressione per questo in Kotlin. In Kotlin ifè un'espressione con un valore di risultato. Quindi in Kotlin possiamo scrivere

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

e in Java possiamo ottenere lo stesso ma con un codice più grande

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

2

Se non fai cosa usare la notazione standard puoi anche crearla / simularla usando infix con qualcosa del genere:

crea una classe per mantenere il tuo obiettivo e il risultato:

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

creare alcune funzioni infix per simulare un'operazione ternaria

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
}

Quindi sarai in grado di usarlo in questo modo:

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"

Per renderlo completamente equivalente a un vero operatore ternario, i valori target possono anche essere lambda fornendo T
Old Man of Aran

1

Un altro breve approccio da usare

val value : String = "Kotlin"

value ?: ""

Qui kotlin stesso controlla un valore nullo e se è nullo passa un valore stringa vuoto.


1

Perché uno dovrebbe usare qualcosa del genere:

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

quando puoi effettivamente usare qualcosa del genere ( aè booleano in questo caso):

when {
  a -> b
  else -> b
}

1
Perché il primo è semanticamente chiaro e facilmente comprensibile a qualcun altro che lo legge anche se non ha familiarità con Kotlin, mentre il secondo no.
mc01

1
Bene, hai ragione, tuttavia non riesco a capire perché gli sviluppatori di Kotlin non abbiano introdotto l'espressione ternaria
ZZ 5

Penso che sia in ? and :contraddizione con la dichiarazione nullable / type piuttosto che un controllo del tipo. A parte ciò, non vedo alcun motivo. Penso che qualcuno avrebbe sicuramente pensato, se ci fosse un controllo di condizione if-else in linea. Aspettiamo e vediamo nelle versioni future.
bh4r4th

1

Quando lavori con apply (), ti sembra molto utile quando gestisci operazioni ternarie, poiché è più elegante e ti dà spazio

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

Con le seguenti funzioni infix posso trattare molti casi d'uso più o meno allo stesso modo in cui può essere fatto in 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

Non esiste un operatore ternario a Kotlin, i più chiusi sono i due casi seguenti,

  • Se altro come espressione di espressione

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

  • Operatore Elvis

Se l'espressione a sinistra di?: Non è nulla, l'operatore elvis la restituisce, altrimenti restituisce l'espressione a destra. Si noti che l'espressione del lato destro viene valutata solo se il lato sinistro è nullo.

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

Documenti di riferimento


0

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

In kotlin se stai usando ?: Funzionerà come se l'istruzione restituirà null allora ?: 0 ci vorrà 0 o qualunque cosa tu abbia scritto da questo lato.


-1

In Kotlin puoi usare l'operazione ternaria in questo modo: val x = if(a) "add b" else "add c"


1
Questa domanda ha già ricevuto una risposta sufficiente e non è stata aggiornata di recente. Non è necessario pubblicare ora un'altra risposta che non differisce da quelle precedenti.
Headcracker

-2

Dopo alcune ricerche su altre idee, ho derivato il seguente operatore ternario:

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

Esempio (esegui qui ):

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

Questa versione è fluente e non è in conflitto con l'operatore di coalescenza nulla.


Questo è un po 'lo stesso della risposta di Deviant dove prende il nome theninvece di yes.
Ry-

@ Sì, e non sono sicuro che siano la stessa persona, ma l'idea di usare i metodi infix con gli optionals proviene dal forum di Kotlin. Quello che non ho visto è il metodo "no" che mi è venuto in mente perché trovo confuso l'uso dell'operatore a coalescenza nulla perché il punto interrogativo è dopo il "valore allora" invece della condizione come nella maggior parte delle lingue.
Bryan W. Wagner,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.