Operador condicional de Kotlin Ternary

Respostas:

618

No Kotlin, ifdeclarações são expressões. Portanto, o seguinte código é equivalente:

if (a) b else c

A distinção entre expressão e afirmação é importante aqui. Em Java / C # / JavaScript, ifforma uma instrução, o que significa que ela não resolve para um valor. Mais concretamente, você não pode atribuí-lo a uma variável.

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

Se você vem de um idioma em que ifhá uma declaração, isso pode parecer pouco natural, mas esse sentimento deve diminuir em breve.

Drew Noakes
fonte
57
Além disso, você pode usar when.
Bashor
5
apenas para adicionar, se é uma expressão booleana, você pode até mesmo ir comx = a==b
gnomeria
2
@ MikeRylander Estendi a resposta para tornar isso explícito. Obrigado por apontar isso.
de Drew Noakes
1
@AdeelAnsari Não, não está retificando. Isto é pior. Compare isso. b + if (a) c else dvs. b + (c if (a) else d)O último requer parênteses adicionais. porque cnão é delimitada pela condição e else.
Naetmul 12/0318
1
Aqui está uma pequena discussão sobre este tópico. discuss.kotlinlang.org/t/ternary-operator/2116/141
F. Norbert
70

Você pode definir sua própria Booleanfunção de extensão que retorna nullquando Booleanfor falsefornecer uma estrutura semelhante ao operador ternário:

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

Isso faria uma a ? b : cexpressão ser traduzida para a then b ?: c, assim:

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

Atualização: Mas, para fazer uma troca condicional semelhante a Java, você precisará de algo assim

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

println(condition then { "yes" } ?: "no") preste atenção na lambda. seu cálculo de conteúdo deve ser adiada até que nós temos certeza conditionétrue

Este parece desajeitado, é por isso que existe uma solicitação muito alta para portar o operador ternário Java no Kotlin

divergente
fonte
1
infix inline fun<T> Boolean.then(param: ()->T):T? = if(this) param() else null
nullbyte 19/10/19
3
Use <T: Any>, caso contrário, isso funcionará incorretamente:true then { null } ?: "not-null"
Eugene Petrenko
BTW, o ?:operador aqui é elvis-operator: kotlinlang.org/docs/reference/null-safety.html#elvis-operator
Eric Wang
64

TL; DR

if (a) b else c

é o que você pode usar em vez da expressão do operador ternário a ? b : c.


Em Kotlin, muitas declarações de controle, incluindo if, whenou até mesmo trypode ser usado como expressões . Isso significa que aqueles podem ter um resultado que pode ser atribuído a uma variável, retornado de uma função etc.

Sintaticamente, não há necessidade de operador ternário

Como resultado das expressões de Kotlin, a linguagem realmente não precisa do operador ternário .

if (a) b else c

é o que você pode usar em vez da expressão do operador ternário a ? b : c.

Penso que a ideia é que a expressão anterior seja mais legível, pois todo mundo sabe o que ifelsefaz, ao passo que não ? :é claro se você ainda não conhece a sintaxe.

No entanto, tenho que admitir que muitas vezes sinto falta do operador ternário mais conveniente.


Outras alternativas

quando

Você também pode ver whenconstruções usadas no Kotlin quando as condições são verificadas. É também uma maneira de expressar o cascalho if-else de uma maneira alternativa. O seguinte corresponde ao exemplo do OTs.

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

Extensões

Como mostram muitos bons exemplos ( Operador condicional do Kotlin Ternary ) nas outras respostas, as extensões também podem ajudar na solução do seu caso de uso.

s1m0nw1
fonte
36

Para mim, eu uso as seguintes funções de extensão:

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

O primeiro retornará o valor padrão fornecido, caso o objeto seja igual a nulo. O segundo avaliará a expressão fornecida em lambda no mesmo caso.

Uso:

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

Pessoalmente, para mim, o código acima é mais legível do que a ifconstrução embutida

ruX
fonte
34
Não é relevante para a questão, mas por que não usar ?: , O operador elvis ? A primeira função seria substituída por e.getMessage() ?: "unknown". O segundo pode ser expresso comoobj?.lastMessage?.timestamp ?: { Date() }()
tecla de atalho
1
@hotkey não existe um objetivo especial para isso. Do meu ponto de vista é aparência mais consistentes e visualmente menos ruidosos em operações da cadeia como você não deve envolver a construção nos suportes
Rux
14
@ruX o operador elvis é especificamente para isso e seu uso é bastante incomum.
Jayson Minard
6
Enquanto?: Está bom, não vamos muito longe no caminho para Perl.
Richard Haven
28

Não há operador ternário no kotlin, pois o if elsebloco retorna valor

então, você pode fazer: em val max = if (a > b) a else b vez de javamax = (a > b) ? b : c

Também podemos usar a whenconstrução, mas também retornamos valor:

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

Aqui está o link para a documentação do kotlin: Fluxo de Controle: se, quando, por, enquanto

romiope
fonte
27

No Kotlin, ifé uma expressão, ou seja, retorna um valor. Portanto, não há operador ternário (condition ? then : else), porque comum se funciona bem nesse papel. fonte manual daqui

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

Alguns casos de canto não mencionados em outras respostas.

Desde a aparência do takeIf no Kotlin 1.1, o operador ternário a ? b : ctambém pode ser expresso assim:

b.takeIf { a } ?: c

Isso fica ainda mais curto caso c seja null:

b.takeIf { a }

Observe também que, no mundo Java, as verificações nulas típicas, como value != null ? value : defaultValuetraduzir no otomático Kotlin para just value ?: defaultValue.

Semelhante a != null ? b : cpode ser traduzido para a?.let { b } ?: c.

Vadzim
fonte
6
Como é b.takeIf { a } ?: cmais curto e mais legível do que if (a) b else c? Terneray operador é certamente uma característica ausente em Kotlin desde nomes de variáveis ea condição pode ser longo e fazer você dividir a linha que é ruim
Javad Sadeqzadeh
1
Também deve ser observado que takeIfsempre avalia o caso real (aqui a). Essa expressão não só pode ser computada inutilmente se afor falsa, mas você não pode se beneficiar de lançamentos inteligentes à la if (a is Int) { a + 3 }.
TheOperator
@ TheOperator, errado. { a }é um lambda avaliado preguiçosamente.
Vadzim
1
Eu escrevi errado, deve ser "sempre avalia o caso verdadeiro (aqui b)". Mas mesmo { a }sendo preguiçoso, deve ser avaliado para determinar o resultado da expressão.
TheOperator 13/08/18
24

Dê uma olhada nos documentos :

No Kotlin, se é uma expressão, ou seja, ele retorna um valor. Portanto, não há operador ternário (condição? Then: else), porque comum se funciona bem nesse papel.

Li Ying
fonte
13

Java

int temp = a ? b : c;

Equivalente a Kotlin:

var temp = if (a) b else c
doubleThunder
fonte
12

TAREFA :

Vamos considerar o seguinte exemplo:

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

Precisamos do seguinte equivalente no Kotlin:

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


SOLUÇÕES :

1.a . Você pode usar if-expressionno Kotlin:

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

1.b . Pode ser muito melhor se você virar isso if-expression(vamos fazê-lo sem not):

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

2 . O operador Elvis da Kotlin ?:pode fazer um trabalho ainda melhor:

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

3 . Ou use um Extension functionpara a Answerclasse correspondente :

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

4 . Usando o Extension functionvocê pode reduzir um código graças a Elvis operator:

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

5 . Ou apenas use o whenoperador:

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

Espero que isto ajude.

Andy
fonte
11

quando substitui o operador do comutador de idiomas do tipo C. Na forma mais simples, parece com isso

when (x) {
    1 -> print("x == 1")
    2 -> print("x == 2")
    else -> {
        print("x is neither 1 nor 2")
    }
}
Guruprasath
fonte
3
É verdade, mas o exemplo que você mostra tem whenuma declaração, não uma expressão. Uma comparação mais relevante com expressões condicionais ternárias seria fazer com que cada ramificação retornasse um valor, de modo que a expressão quando inteira fosse avaliada como um valor (como acontece com as condicionais ternárias).
Drew Noakes
9

Não há operador ternário em Kotlin. Parece problemático à primeira vista. Mas pense que podemos fazê-lo com a instrução inline if else, porque esta é a expressão aqui. Simplesmente temos que fazer -

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

Aqui, podemos outra coisa se bloquearmos o número necessário. Gostar-

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

Portanto, essa linha é tão simples e muito legível que o operador ternário. quando usamos mais de um operador ternário em java, isso parece horrível. Mas aqui temos uma sintaxe clara. até nós podemos escrever em várias linhas também.

HM Nayem
fonte
9

Você pode usar var a= if (a) b else c no lugar do operador ternário.

Outro bom conceito de kotlin é o operador de Elvis. Você não precisa verificar nulo sempre.

val l = b?.length ?: -1

Isso retornará length se b não for nulo, caso contrário, ele executará a instrução do lado direito.

Android Geek
fonte
7

como Drew Noakes citou, o kotlin usa if declaração como expressão, portanto o Operador Condicional Ternário não é mais necessário,

mas com a função de extensão e sobrecarga de infix, você pode implementar isso sozinho, aqui está um exemplo

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
}

então use-o assim

val grade = 90
val clazz = (grade > 80) then "A" or "B"
Minami
fonte
Talvez remover <T> melhor diversão infix ou (Falsas: T)? = If (flag) realmente outra coisa Falsas
solo de
1
Mas adicionar <T> pode fazê-lo funcionar: (grau> 80), em seguida, nulo ou "B"
solo de
Isso é muito legal, eu vou usá-lo: P Mas observe que, a menos que eu esteja enganado, isso causará uma alocação de objeto sempre que for chamado. Não é um grande negócio, mas vale a pena saber que não é uma abstração de custo zero.
Adam
6

Outra abordagem interessante seria usar when:

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

Pode ser bastante útil em alguns cenários mais complexos. E honestamente, é mais legível para mim do queif ... else ...

Grzegorz Piwowarek
fonte
6

Você pode fazer isso de várias maneiras em Kotlin

  1. Usando se

    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. Segurança nula

    val a = b ?: c
Rajesh Dalsaniya
fonte
5

Não existe uma operação ternária no Kotlin, mas existem algumas maneiras divertidas de contornar isso. Como outros já apontaram, uma tradução direta para o Kotlin seria assim:

val x = if (condition) result1 else result2

Mas, pessoalmente, acho que isso pode ficar um pouco confuso e difícil de ler. Existem outras opções embutidas na biblioteca. Você pode usar o takeIf {} com um operador elvis:

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

O que está acontecendo lá é que o comando takeIf {} retorna seu resultado1 ou nulo, e o operador elvis lida com a opção nula. Existem algumas opções adicionais, takeUnless {}, por exemplo:

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

A linguagem é clara, você sabe o que está fazendo.

Se for uma condição comumente usada, você também pode fazer algo divertido, como usar um método de extensão em linha. Vamos supor que desejamos rastrear uma pontuação do jogo como um Int, por exemplo, e queremos sempre retornar 0 se uma determinada condição não for atendida:

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

Ok, isso parece feio. Mas considere como fica quando é usado:

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

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

Como você pode ver, o Kotlin oferece muita flexibilidade na maneira como você escolhe expressar seu código. Existem inúmeras variações dos meus exemplos e, provavelmente, maneiras que ainda nem descobri. Eu espero que isso ajude!

pranalli
fonte
takeIfé minha opção favorita, de fato, muito elegante.
Javier Mendonça
4

Lembre-se de operador Ternary e operador Elvis possuem significados separados no Kotlin, diferentemente de muitos idiomas populares. Fazer expression? value1: value2daria a você palavrões pelo compilador Kotlin , diferente de qualquer outro idioma, pois não há um operador ternário no Kotlin, conforme mencionado nos documentos oficiais . O motivo é que as próprias declarações if, when e try-catch retornam valores.

Então, fazer expression? value1: value2pode ser substituído por

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

O operador Elvis que Kotlin possui, funciona apenas no caso de variáveis ​​anuláveis, ex .:

Se eu fizer algo assim value3 = value1 ?: value2, se value1 for nulo , value2 será retornado, caso contrário value1 seria retornado.

Um entendimento mais claro pode ser alcançado com essas respostas .

Neeraj Sewani
fonte
3

Você pode usar ifexpressão para isso no Kotlin. No Kotlin ifé uma expressão com um valor de resultado. Então, em Kotlin, podemos escrever

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

e em Java podemos conseguir o mesmo, mas com código maior

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

Se você não fizer o que usar a notação padrão, também poderá criar / simular usando infix com algo como isto:

crie uma classe para manter sua meta e resultado:

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

crie algumas funções infix para simular uma operação ternária

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
}

Então você poderá usá-lo assim:

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
fonte
Para que seja completamente equivalente a um operador ternário real, os valores-alvo também podem ser lambda, fornecendo T
Old Man of Aran
1

Outra abordagem curta para usar

val value : String = "Kotlin"

value ?: ""

Aqui, o próprio kotlin verifica o valor nulo e, se for nulo, passa o valor da string vazia.

Vinod Pattanshetti
fonte
1

Por que alguém usaria algo assim:

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

quando você pode realmente usar algo assim ( aneste caso, é booleano):

when {
  a -> b
  else -> b
}
ZZ 5
fonte
1
Porque o primeiro é semanticamente claro e facilmente compreensível para alguém que o esteja lendo, mesmo que não esteja familiarizado com o Kotlin, enquanto o segundo não é.
Mc01 # 16/18
1
Bem, você tem o ponto, no entanto eu não consigo entender por que os desenvolvedores KOTLIN não introduzir ternário expressão
ZZ 5
Eu acho que ? and :contradiz com a declaração anulável / tipo, em vez de uma verificação de tipo. Além disso, não vejo motivo. Eu acho que alguém definitivamente pensaria um pouco, se houver uma verificação de condição em caso contrário. Vamos esperar e ver nas versões futuras.
bh4r4th 04/02
1

Ao trabalhar com apply (), deixe parecer muito útil ao lidar com operações ternárias, pois é mais elegante e oferece espaço para você

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
fonte
0

Com as seguintes funções infix, posso cobrir muitos casos de uso comuns da mesma maneira que em 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
fonte
0

Não há operador ternário em Kotlin; os mais fechados são os dois casos abaixo,

  • Se mais como declaração de expressão

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

  • Operador Elvis

Se a expressão à esquerda de?: Não for nula, o operador elvis a retornará, caso contrário, ela retornará a expressão à direita. Observe que a expressão do lado direito é avaliada apenas se o lado esquerdo for nulo.

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

Documentos de referência

JTeam
fonte
0

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

No kotlin, se você estiver usando ?: Funcionará como se a instrução retornasse nula, então :: 0 levará 0 ou o que quer que você tenha escrito deste lado.

abhilasha Yadav
fonte
-1

No Kotlin você pode usar operações ternárias como esta: val x = if(a) "add b" else "add c"

manuelernest0
fonte
1
Esta pergunta já foi respondida o suficiente e não foi atualizada recentemente. Não há necessidade de postar agora outra resposta que não difere das anteriores.
Headcracker
-2

Depois de pesquisar outras idéias, deduzi o seguinte operador ternário:

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

Exemplo (execute aqui ):

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

Esta versão é fluente e não entra em conflito com o operador coalescente nulo.

Bryan W. Wagner
fonte
É o mesmo que a resposta do desvio, onde é nomeado em thenvez de yes.
Ry-
@ Sim, e não tenho certeza se são a mesma pessoa, mas a idéia de usar métodos infix com opcionais vem do fórum do Kotlin. O que eu não vi é o método 'não' que eu criei porque acho confuso o uso em linha do operador coalescente nulo, porque o ponto de interrogação está depois do 'then value' em vez da condição como na maioria dos idiomas.
Bryan W. Wagner