Sobrecarga de operadores do Kotlin

alexfelipe

Alex Felipe

Posted on June 6, 2023

Sobrecarga de operadores do Kotlin

Um detalhe bastante curioso no Kotlin é que podemos "somar", "subtrair" ou fazer diversas operações com os nossos objetos. Um exemplo bastante interessante seria a soma de listas:

val words = listOf("alex", "felipe")
val numbers = listOf(1, 2, 3)
val someList = words + numbers
println(someList)
println(words)
println(numbers)
Enter fullscreen mode Exit fullscreen mode

Qual o resultado você espera? Vejamos:

[alex, felipe, 1, 2, 3]
[alex, felipe]
[1, 2, 3]
Enter fullscreen mode Exit fullscreen mode

Olha que interessante! Uma nova lista foi criada adicionando os itens de cada lista, e mais, a soma não é restrita apenas entre as listas, podemos somar com qualquer objeto, até mesmo os nossos:

data class User(
    val id: Long,
    val name: String
)

val numbersWithUser = listOf(1, 2) + User(
    id = 1,
    name = "alexfelipe"
)
val wordsWithNumber = listOf(
    "alex",
    "felipe"
) + 1
println(numbersWithUser)
println(wordsWithNumber)
Enter fullscreen mode Exit fullscreen mode

E o resultado que temos é:

[1, 2, User(id=1, name=alexfelipe)]
[alex, felipe, 1]
Enter fullscreen mode Exit fullscreen mode

Neste momento você pode pensar:

"Como isso é possível?" 🤔

Conhecendo a sobrecarga de operadores

Essa funcionalidade é conhecida como sobrecarga de operadores ou operator overloading, embora o nome poça assustar, basicamente, são métodos "especiais" com a keyword operator que permitem adicionar o comportamento que desejamos.

Vamos considerar o exemplo do +, ele é traduzido para o método plus(). Podemos até mesmo ver algumas implementações na interface de Collection:

public operator fun <T> Collection<T>.plus(element: T): List<T> {
    val result = ArrayList<T>(size + 1)
    result.addAll(this)
    result.add(element)
    return result
}

public operator fun <T> Iterable<T>.plus(elements: Iterable<T>): List<T> {
    if (this is Collection) return this.plus(elements)
    val result = ArrayList<T>()
    result.addAll(this)
    result.addAll(elements)
    return result
}
Enter fullscreen mode Exit fullscreen mode

Veja que tem mais de uma implementação e é por isso que podemos somar listas com listas ou listas com objetos e por ai vai... Aqui você pode ver alguns operadores comuns:

Expressão Traduzido para
a + b a.plus(b)
a - b a.minus(b)
a * b a.times(b)
a / b a.rem(b)
a..b a.rangeTo(b)

Em outras palavras, se você é capaz de fazer alguma dessas operações com objetos em Kotlin, é porque existe essa sobrecarga!

Implementando sobrecarga de operadores

Inclusive, podemos implementar operadores em nossas classes:

data class Product(
    val id: Long,
    val name: String,
    val description: String
)

class Cart(
   val products: List<Product> = listOf()
) {
    operator fun plus(product: Product): Cart =
        Cart(products + product)
}
Enter fullscreen mode Exit fullscreen mode

Nesta implementação, podemos criar novos carrinhos com os produtos que desejamos somar:

val cart = Cart()
val cartWithKeyboard = cart + Product(
    id = 1,
    name = "Teclado mecânico",
    description = "Teclado com switches brown"
)
println(cartWithKeyboard.products)
val cartWithTShirt = cartWithKeyboard + Product(
    id = 2,
    name = "Camiseta",
    description = "Material 100% algodão"
)
println(cartWithTShirt.products)
Enter fullscreen mode Exit fullscreen mode

Olha só o resultado que temos:

[Product(id=1, name=Teclado mecânico, description=Teclado com switches brown)]
[Product(id=1, name=Teclado mecânico, description=Teclado com switches brown), Product(id=2, name=Camiseta, description=Material 100% algodão)]
Enter fullscreen mode Exit fullscreen mode

Interessante, né? Outras possibilidades de implementação seriam:

  • somar objetos de pedidos e o retorno ser um resumo com todos os produtos, quantidades e valores somados.
  • somar objetos de pagamentos ou taxas para obter o valor final com as adições
  • somar um usuário e um produto para criar um pedido

Enfim, uma série de ações comuns no nosso dia a dia.

Outros casos de uso de operadores

Atualmente existem diversas implementações de operadores, se observarmos a própria Collection, identificamos que é possível subtrair também:

val words = listOf("alex", "felipe", "instrutor", "alura") - "felipe"
val numbers = listOf(1, 2, 3) - 2
println(words)
println(numbers)
Enter fullscreen mode Exit fullscreen mode

Veja o resultado:

[alex, instrutor, alura]
[1, 3]
Enter fullscreen mode Exit fullscreen mode

Ou seja, uma forma mais sucinta de criar uma lista nova sem os elementos que não queremos!

E não para por aqui, se pegarmos classes como BigDecimal, podemos até mesmo fazer operações aritméticas sem problemas:

val total = BigDecimal("2.99") + BigDecimal("4.35")
println(total)
Enter fullscreen mode Exit fullscreen mode

E chegamos no seguinte resultado:

7.34
Enter fullscreen mode Exit fullscreen mode

O mesmo resultado sem a sobrecarga de operador seria assim:

val total = BigDecimal("2.99")
    .add(BigDecimal("4.35"))
Enter fullscreen mode Exit fullscreen mode

Para saber mais: outros tipos de operadores

Neste artigo foquei na sobrecarga de operadores aritméticos, mas existem outras possibilidades, operações unárias e binárias, sendo que as aritméticas fazem parte das binárias.

O que achou da sobrecarga de operadores no Kotlin? Já usava no seu código? Compartilhe sua experiência nos comentários

💖 💪 🙅 🚩
alexfelipe
Alex Felipe

Posted on June 6, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related