Estruturas de controle em Kotlin
Tags: kotlin, java
Published: 2022-11-08 03:10:30

Kotlin, assim como outras linguagens de programação de alto nível, tem estruturas de controle básicas como `while`, `for` e `if`. No post de hoje vamos conhecê-las e aprender sobre a estrutura substituta do `switch`, o `when`.

## Estrutura `while`

Essa estrutura de controle é bem similar ao Java, sendo praticamente idêntica. Além de `while`, também temos sua irmã, a estrutura `do-while`.  Como são muito parecidas com as em Java, vamos analisar brevemente dois códigos sobre elas.

A estrutura `while` tem o seguinte formato:

```kotlin
fun main() {
	var palavra = ""
	
	while(palavra.length <= 10) {
		palavra += 'z'
	}
}
```

Ou seja, o programa irá executar repetidamente uma ou mais linhas de código enquanto uma condição for atendida. No caso acima, o loop irá ocorrer até que o tamanho da string seja menor ou igual a 10, o loop irá cessar quando a palavra alcançar o tamanho 11.

Por outro lado, a estrutura `do-while` tem o seguinte formato:

```kotlin
fun main() {
	var palavra = ""

	do {
		palavra += 'z'
	} while(palavra.length != 0)
}
```

Enquanto na estrutura `while`, não temos a garantia de que o loop será executado, na `do-while` sabemos que ele ocorre ao menos uma vez. Como podemos ver acima, primeiro incrementamos a palavra em um caractere e depois comparamos se seu tamanho é diferente de zero, o que ocasiona em um loop infinito, visto que seu tamanho sempre será diferente de zero. No entanto, se usássemos `while`, isso não teria ocorrido, já que a comparação teria sido feita antes do incremento.

## Estrutura `for`

Diferentemente de `while` e `do-while`, a estrutura de controle `for` em Kotlin é diferente da em Java e tem várias formas de uso específico, como iterar sobre um intervalo ou uma coleção.

### Iterando sobre intervalos

Se quisermos imprimir todos os números naturais (incluindo o zero) até um certo outro número natural, excluindo ele mesmo, como podemos fazer em Kotlin? Podemos usar o operador `..` entre zero e o determinado número menos 1. Esse operador indica que estamos usando um intervalo entre dois valores:

```kotlin
import kotlin.random.Random

fun main() {
	val numeroRandom = Random.nextInt(0, 100)
	
	for(i in 0 .. numeroRandom-1) {
		println(i)
	}
}
```

No código acima, primeiro obtemos um número pseudo-randômico entre 0 e 100 e depois usamos for com o operador `..` pra indicar que iremos iterar sobre esse intervalo, além de utilizarmos o operador `in` que garante que o valor de `i` esteja no intervalo especificado. Podemos deixar esse código mais idiomático usando a função `until`, que simula esse comportamento de `0 (intervalo) valor - 1`:

```kotlin
import kotlin.random.Random

fun main() {
	val numeroRandom = Random.nextInt(0, 100)
	
	for(i in 0 until numeroRandom) {
		println(i)
	}
}
```

Também podemos iterar sobre intervalos utilizando outros funções como `downTo` e `step`. Se queremos imprimir todos os número pares entre 100 e 0, podemos fazer o seguinte:

```kotlin
fun main() {

	for(i in 100 downTo 0 step 2) {
		println(i)
	}
}
```

A função `downTo` indica que o intervalo é de trás para frente e a função `step` faz com que dois números sejam pulados a cada iteração, assim, imprimindo apenas os números pares. Essa função está presente em todos esses `for`s que envolvem intervalo, quando não a utilizamos explicitamente ela tem o comportamento padrão de pular um número de cada vez, ou seja `step 1`.

### Iterando sobre coleções

Assim como em Java, também podemos iterar sobre coleções (estruturas de dados de alto nível) em Kotlin, fazendo um trabalho semelhante ao `forEach()`.  Vamos fazer um programa que adiciona os quadrados dos números de uma lista de inteiros em outra:

```kotlin
fun main() {

  val numeros = listOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
  val numerosQuadrados = mutableListOf<Int>()
    
  for(numero in numeros)
      numerosQuadrados.add(numero * numero)
    
  println(numerosQuadrados)
}
```

Note que também usamos o operador `in` para iterar sobre a lista, basicamente desempacotando cada número da lista em uma variável chamada `numero`. Também podemos usar o `in` para iterar sobre caracteres:

```kotlin
fun main() {

    val palavra = "Palavra"
    var palavraEmMaiusculas = ""
    
    for(letra in palavra) {
		palavraEmMaiusculas += letra.toUpperCase()
    }
    
    println(palavraEmMaiusculas)
}
```

No código acima, nós iteramos sobre uma string e adicionamos cada caractere dela como uma letra maiúscula em outra string.

## Estrutura `if`

De forma semelhante a `while`, a estrutura de controla `if` é praticamente idêntica a sua equivalente em Java, o que muda aqui é, conforme estudamos no último post, em Kotlin `if` não é um **statement**, mas sim uma expressão, ou seja, ela tem um retorno. Vamos analisar a função abaixo:

```kotlin
fun ePar(numero: Int): Boolean {
	return if(numero % 2 == 0) {
		true
	} else {
		false
	}
}
```

O que fazemos aqui é retorna o resultado da expressão `if` que compara se um número inteiro, quando divido por 2, deixa resto zero. Também podemos fazer uma estrutura `if` aninhada em Kotlin, usando `else if`:

```kotlin
fun compara(A: Int, B: Int): String {
	return if(A > B) {
		"$A é maior que $B"
	} else if(A < B) {
		"$A é menor que $B"
	} else {
		"$A e $B são iguais"
	}
}
```

## Estrutura `when`

A estrutura `when` é uma substituta para o `if` em alguns casos, ela funciona como um `switch` em Java e assim como o `if` ela pode ter ramificações e retornar valores. Vamos reescrever os dois últimos códigos usando `when`:

```kotlin
fun eParWhen(numero: Int) =
	when {
		numero % 2 == 0 -> {
			true
		}
		else -> false
	}

fun comparaWhen(A: Int, B: Int) =
	when {
		A > B -> "$A é maior que $B"
		A < B -> "$A é menor que $B"
		else -> "$A e $B são iguais"
	}
```

A estrutura `when` é muito útil para se lidar com `Enums`, vamos analisar um exemplo do **Kotlin in Action**. Primeiro vamos criar a enum `Color` que irá representar cores no formato RGB:

```kotlin
enum class Color(
	val red: Int, val green: Int, val blue: Int
) {
	RED(255, 0, 0), ORANGE(255, 165, 0), YELLOW(255, 255, 0), GREEN(0, 255, 0),
	BLUE(0, 0, 255), INDIGO(75, 0, 130), VIOLET(238, 130, 238), WHITE(255, 255, 255);

	fun rgb() = (red * 256 + green) * 256 + blue
}
```

Como pode ver, além de constantes, uma enum em Kotlin pode ter propriedades e funções, em adição a isso esse exemplo também mostra o único caso de uso de ponto e vírgula em Kotlin: para separar as constantes de uma enum das suas funções. 

As constantes que foram definidas representam certas cores para certos valores das três propriedades e a função `rgb()` retorna a ordem dessa cor na gama de cores que podem ser representadas no formato RGB. 

Por exemplo, se usarmos essa função para a cor `BLUE`, veremos que ela é a cor de número 255, agora se usarmos para a cor `WHITE`, podemos observar que ela é a cor de número 16777215, ou seja, a última cor, já que podem ser representadas pouco mais de 16 milhões de cores em RGB.

Agora vamos usar `when` para facilitar a nossa vida: caso precisássemos fazer uma função que retorna a "temperatura” de um certa cor, como faríamos ser usar vários `if`s? Simples:

```kotlin
fun obtemTemperaturaCor(color: Color) =
	when(color) {
			Color.RED, Color.ORANGE, Color.YELLOW -> "Quente"
			Color.GREEN -> "Neutra"
			Color.BLUE, Color.INDIGO, Color.INDIGO, Color.VIOLET, Color.WHITE -> "Fria"	
	}
```

Veja só que beleza: podemos até combinar múltiplos valores em uma única ramificação, não é incrível 🤩?

Sendo assim, podemos observar que a forma dessa estrutura é a seguinte:

```kotlin
when (valorOpcional) {
	condicao1 -> {
		// faz alguma coisa
	}
	condicao2 -> {
		//faz outra coisa
	}
	else -> { // else opcional
		// faz algo
	}
}
```

Diferentemente do `switch`, não somos obrigados a passar o valor que será comparado entre parênteses e nem escrever declarações `break` ao fim de cada ramificação.  

## Próximos posts

Nos próximos posts vamos nos aprofundar no estudo de funções e estudar classes, objetos e interfaces. Obrigado pela atenção, até a próxima!

Post anterior:

{% embed https://dev.to/ronaldocoding/introducao-ao-kotlin-19cj %}

Próximo post:

{% embed https://dev.to/ronaldocoding/interfaces-em-kotlin-4jdo %}