Kotlin4Noobs

Buscar nas notas

    fun

    Funções

    Declaração, parâmetros, retorno e funções de expressão única.

    Sintaxe

    Em Kotlin, as funções são declaradas usando a palavra-chave fun:

    fun add() {
        // ...  
    }

    Você pode definir parâmetros para a função usando a notação Pascal, name: type. Os parâmetros são separados por vírgulas, e cada parâmetro deve ser explicitamente tipado:

    fun add(augend: Int, addend: Int): Int {
        return augend + addend
    }

    Quando uma função retorna uma única expressão, as chaves podem ser omitidas, e o corpo é especificado após um =:

    fun add(augend: Int, addend: Int): Int = augend + addend

    Para fazer a chamada da função:

    add(1, 1)

    Ou usando argumentos nomeados:

    add(augend = 1, addend = 1)

    Exemplo completo:

    fun add(augend: Int, addend: Int): Int = augend + addend
    
    fun main() {
        println(add(1, 1))                    // 2
        println(add(augend = 1, addend = 1))  // 2
    }

    Nota

    Usar argumentos nomeados pode ser útil quando uma função tem muitos parâmetros, facilitando a associação de valores aos argumentos.

    Funções de extensão

    Kotlin permite adicionar funcionalidades a classes existentes sem alterá-las diretamente, usando extension functions.
    Isso é útil para estender o comportamento de objetos existentes sem modificá-los ou criar novos tipos.

    Para criar uma função de extensão, a sintaxe é:

    fun ClassName.newFunctionName(arguments.. .) {
        // ...
    }

    Vamos criar uma função de extensão chamada screaming para a classe String, que retorna a string em letras maiúsculas, seguida por três pontos de exclamação:

    fun String.screaming(): String = uppercase() + "!!!"
    
    "Hello World".screaming()

    Exemplo completo:

    fun String.screaming(): String = uppercase() + "!!!"
    
    fun main() {
        println("Hello World".screaming())  // HELLO WORLD!!!
    }

    Operadores aritméticos

    Kotlin permite que você sobrescreva operadores, fornecendo implementações personalizadas para operadores como + ou *. Essas funções são declaradas usando operator fun:

    data class BigNumber(val value: Int) {
    
        operator fun div(divisor: BigNumber): Int = value / divisor.value
    
        operator fun plus(addend: BigNumber): Int = value + addend.value
    
        operator fun minus(subtrahend: BigNumber): Int = value - subtrahend.value
    
        operator fun times(multiplier: BigNumber): Int = value * multiplier.value
    }

    Exemplo completo:

    data class BigNumber(val value: Int) {
        operator fun div(divisor: BigNumber): Int = value / divisor.value
        operator fun plus(addend: BigNumber): Int = value + addend.value
        operator fun minus(subtrahend: BigNumber): Int = value - subtrahend.value
        operator fun times(multiplier: BigNumber): Int = value * multiplier.value
    }
    
    fun main() {
        val a = BigNumber(10)
        val b = BigNumber(5)
        
        println(a + b)  // 15
        println(a - b)  // 5
        println(a * b)  // 50
        println(a / b)  // 2
    }

    Funções de alta ordem e lambdas

    Funções de alta ordem

    Em Kotlin, funções podem ser tratadas como cidadãos de primeira classe, ou seja, podem ser usadas como argumentos ou valores de retorno de outras funções.

    Como Kotlin é uma linguagem estaticamente tipada, você precisa definir os tipos dos parâmetros e do retorno da função, usando function types.

    fun applyDiscount(discount: Int): (Double) -> Double {
        val percentage = discount.toDouble() / 100
    
        return { value -> value - (percentage * value) }
    }

    Aqui, a função applyDiscount retorna uma função que recebe um Double e também retorna um Double.

    val discountOf15Percent = applyDiscount(discount = 15)
    var amount = 3459.99
    
    amount = discountOf15Percent(amount)

    Exemplo completo:

    fun applyDiscount(discount: Int): (Double) -> Double {
        val percentage = discount.toDouble() / 100
        return { value -> value - (percentage * value) }
    }
    
    fun main() {
        val discountOf15Percent = applyDiscount(discount = 15)
        var amount = 3459.99
        
        amount = discountOf15Percent(amount)
        println(amount)  // 2940.9915
    }

    Lambdas

    Funções podem ser instanciadas de duas maneiras: usando expressões lambda ou funções anônimas.

    val plusOneLambda = { value: Int -> value + 1 }
    
    val plusOneAnonymous = fun(value: Int): Int {
        return value + 1
    }

    Essas funções podem ser invocadas diretamente ou usando o operator invoke:

    plusOneLambda(1)
    plusOneLambda.invoke(1)
    
    plusOneAnonymous(2)
    plusOneAnonymous.invoke(2)

    Também é possível criar tipos nomeados para funções usando typealias:

    typealias Sum = (Int) -> Int
    
    val plusOneLambda: Sum = { value: Int -> value + 1 }

    Exemplo completo:

    typealias Sum = (Int) -> Int
    
    fun main() {
        val plusOneLambda: Sum = { value: Int -> value + 1 }
        
        val plusOneAnonymous = fun(value: Int): Int {
            return value + 1
        }
        
        println(plusOneLambda(1))           // 2
        println(plusOneLambda.invoke(1))    // 2
        println(plusOneAnonymous(2))        // 3
        println(plusOneAnonymous.invoke(2)) // 3
    }