Criar e usar funções em Kotlin

1. Antes de começar

Em um codelab anterior, você viu um programa simples que mostrou a mensagem Hello, world!. Nos programas criados até agora, você aprendeu sobre duas funções:

  • Uma função principal main(), que é necessária em todo programa Kotlin. Ela é o ponto de entrada, ou ponto de partida, do programa.
  • Uma função println(), chamada na função main() para gerar texto.

Neste codelab, você vai aprender mais sobre funções.

As funções permitem dividir o código em partes reutilizáveis, em vez de incluir tudo na função main(). Elas são um elemento essencial dos apps Android, e saber como definir e usá-las é muito importante na jornada para se tornar um desenvolvedor Android.

Pré-requisitos

  • Conhecimentos básicos de programação em Kotlin, incluindo variáveis e as funções println() e main().

O que você vai aprender

  • Como definir e chamar suas próprias funções.
  • Como retornar de uma função valores que podem ser armazenados em uma variável.
  • Como definir e chamar funções com vários parâmetros.
  • Como chamar funções com argumentos nomeados.
  • Como definir valores padrão para parâmetros de função.

O que é necessário

  • Um navegador da Web com acesso ao Playground Kotlin.

2. Definir e chamar uma função

Antes de conhecer mais a fundo as funções, vamos revisar alguns termos básicos.

  • A declaração (ou definição) de uma função usa a palavra-chave fun e inclui o código entre chaves, que contém as instruções necessárias para executar uma tarefa.
  • Chamar uma função faz com que todo o código contido nessa função seja executado.

Até agora, você escreveu todo o código na função main(). Essa função não é chamada em nenhum lugar do código. O compilador Kotlin a usa como ponto de partida. A main() é usada apenas para incluir outros códigos que você quer executar, como chamadas para a função println().

A função println() faz parte da linguagem Kotlin. No entanto, é possível definir suas próprias funções. Isso permite que o código seja reutilizado se precisar ser chamado mais de uma vez. Veja o exemplo do programa abaixo.

fun main() {
    println("Happy Birthday, Rover!")
    println("You are now 5 years old!")
}

A função main() consiste em duas instruções println(): uma para desejar ao Rover um feliz aniversário e outra que indica a idade dele.

Embora o Kotlin permita colocar todo o código na função main(), talvez você nem sempre queira fazer isso. Por exemplo, se você também quiser que o programa contenha uma felicitação de ano-novo, a função principal também teria que incluir essas chamadas para println(). Ou talvez você queira dar parabéns ao Rover várias vezes. É possível simplesmente copiar e colar o código ou criar uma função separada para dar os parabéns. Você vai fazer a segunda opção. A criação de funções separadas para tarefas específicas oferece vários benefícios.

  • Código reutilizável: em vez de copiar e colar códigos que você precisa usar mais de uma vez, basta chamar uma função sempre que necessário.
  • Legibilidade: garantir que funções realizem apenas uma tarefa específica ajuda outros desenvolvedores, colegas de equipe e até mesmo você no futuro a saber exatamente o que um código faz.

A sintaxe para definir uma função é mostrada no diagrama abaixo.

Sintaxe para definir uma função

Para definir uma função, comece com a palavra-chave fun, seguida pelo nome da função, um conjunto de parênteses de abertura e fechamento e um conjunto de chaves de abertura e fechamento. O código entre chaves é aquele que vai ser executado quando a função for chamada.

Você vai criar uma nova função para remover as duas instruções println() da função main().

  1. No navegador, abra o Playground Kotlin e substitua o conteúdo pelo código abaixo.
fun main() {
    println("Happy Birthday, Rover!")
    println("You are now 5 years old!")
}
  1. Após a função main(), defina uma nova função chamada birthdayGreeting(). Essa função é declarada com a mesma sintaxe da função main().
fun main() {
    println("Happy Birthday, Rover!")
    println("You are now 5 years old!")
}

fun birthdayGreeting() {

}
  1. Mova as duas instruções println() de main() para entre as chaves da função birthdayGreeting().
fun main() {

}

fun birthdayGreeting() {
    println("Happy Birthday, Rover!")
    println("You are now 5 years old!")
}
  1. Na função main(), chame a birthdayGreeting(). O código finalizado ficará assim:
fun main() {
    birthdayGreeting()
}

fun birthdayGreeting() {
    println("Happy Birthday, Rover!")
    println("You are now 5 years old!")
}
  1. Execute o código. A saída será esta:
Happy Birthday, Rover!
You are now 5 years old!

3. Retornar um valor de uma função

Em apps mais complexos, as funções fazem mais do que mostrar um texto.

As funções do Kotlin também podem gerar dados conhecidos como valores de retorno, que são armazenados em uma variável que pode ser usada em outro lugar no código.

Ao definir uma função, é possível especificar o tipo de dado do valor que você quer que ela retorne. O tipo de retorno é especificado colocando dois-pontos (:) após os parênteses, um único espaço em branco e, em seguida, o nome do tipo (Int, String etc.). Um único espaço é colocado entre o tipo de retorno e a chave de abertura. No corpo da função, depois de todas as instruções, você vai usar uma instrução de retorno para especificar o valor que a função retornará. Uma instrução de retorno consiste na palavra-chave return, seguida pelo valor, como uma variável, que você quer que a função retorne como saída.

A sintaxe para declarar uma função com um tipo de retorno é mostrada abaixo.

Sintaxe para declarar uma função com um tipo de retorno

O tipo Unit

Se você não especificar um tipo de retorno, o tipo padrão será Unit. Isso significa que a função não retorna um valor. O Unit é equivalente a tipos de retorno nulo em outras linguagens, como void em Java e C; Void/tupla vazia () em Swift; None em Python etc. Qualquer função que não retorne um valor, vai retornar Unit implicitamente. Você pode observar isso ao modificar o código para retornar Unit.

  1. Ao declarar a função birthdayGreeting(), adicione dois pontos após o parêntese de fechamento e especifique o tipo de retorno como Unit.
fun main() {
    birthdayGreeting()
}

fun birthdayGreeting(): Unit {
    println("Happy Birthday, Rover!")
    println("You are now 5 years old!")
}
  1. Execute o código e observe que tudo ainda funciona.
Happy Birthday, Rover!
You are now 5 years old!

Especificar o tipo de retorno Unit em Kotlin é opcional. Para funções que não retornam nada ou retornam Unit, não é necessário ter uma instrução de retorno.

Retornar uma String com a função birthdayGreeting()

Para demonstrar como uma função pode retornar um valor, você vai modificar a função birthdayGreeting() para retornar uma string, em vez de simplesmente mostrar o resultado.

  1. Substitua o tipo de retorno Unit por String.
fun birthdayGreeting(): String {
    println("Happy Birthday, Rover!")
    println("You are now 5 years old!")
}
  1. Execute o código. Você vai encontrar um erro. Se você declarar um tipo de retorno para uma função (por exemplo, String), essa função precisará incluir uma instrução de return.
A 'return' expression required in a function with a block body ('{...}')
  1. Só é possível retornar uma única string de uma função, não duas. Substitua as instruções println() por duas variáveis, nameGreeting e ageGreeting,, usando a palavra-chave val. Como você removeu as chamadas para println() da função birthdayGreeting(), chamar birthdayGreeting() não faz nada ser mostrado na tela.
fun birthdayGreeting(): String {
    val nameGreeting = "Happy Birthday, Rover!"
    val ageGreeting = "You are now 5 years old!"
}
  1. Usando a sintaxe de formatação de string que você aprendeu em um codelab anterior, adicione uma instrução return para retornar uma string da função que consiste em ambas as mensagens de parabéns.

Para formatar as mensagens em uma linha separada, também é necessário usar o caractere de escape \n. Ele funciona como o caractere de escape \" que você conheceu em um codelab anterior. O caractere \n é substituído por uma nova linha para que as duas mensagens fiquem em linhas separadas.

fun birthdayGreeting(): String {
    val nameGreeting = "Happy Birthday, Rover!"
    val ageGreeting = "You are now 5 years old!"
    return "$nameGreeting\n$ageGreeting"
}
  1. Na função main(), como birthdayGreeting() retorna um valor, é possível armazenar o resultado em uma variável de string. Declare uma variável para a mensagem de greeting usando val e armazene o resultado da chamada da birthdayGreeting().
fun main() {
    val greeting = birthdayGreeting()
}
  1. Na função main(), chame println() para mostrar a string greeting. A função main() agora terá a seguinte aparência.
fun main() {
    val greeting = birthdayGreeting()
    println(greeting)
}
  1. Execute o código e observe que o resultado é o mesmo de antes. Retornar um valor permite armazenar o resultado em uma variável, mas o que você acha que vai acontecer se você chamar a função birthdayGreeting() dentro da println()?
Happy Birthday, Rover!
You are now 5 years old!
  1. Remova a variável e transmita o resultado da chamada da função birthdayGreeting() na função println():
fun main() {
    println(birthdayGreeting())
}
  1. Execute o código e observe a saída. O valor de retorno da chamada birthdayGreeting() é transmitido diretamente para println().
Happy Birthday, Rover!
You are now 5 years old!

4. Adicionar um parâmetro à função birthdayGreeting()

Como visto anteriormente, ao chamar println(), você pode incluir uma string entre parênteses ou transmitir um valor para a função. O mesmo pode ser feito com a função birthdayGreeting(). No entanto, primeiro é preciso adicionar um parâmetro à birthdayGreeting().

Um parâmetro especifica o nome de uma variável e um tipo de dado que você pode transmitir para uma função como os dados que serão acessados dentro dela. Os parâmetros são declarados entre parênteses após o nome da função.

Sintaxe para declarar uma função com parâmetros e um tipo de retorno

Cada parâmetro consiste em um nome de variável e um tipo de dado, separados por dois-pontos e um espaço. Vários parâmetros são separados por uma vírgula.

No momento, a função birthdayGreeting() só pode ser usada para dar parabéns ao Rover. Adicione um parâmetro à função birthdayGreeting() para que você possa dar parabéns a qualquer nome transmitido à função.

  1. Dentro dos parênteses da função birthdayGreeting(), adicione um parâmetro name do tipo String usando a sintaxe name: String.
fun birthdayGreeting(name: String): String {
    val nameGreeting = "Happy Birthday, Rover!"
    val ageGreeting = "You are now 5 years old!"
    return "$nameGreeting\n$ageGreeting"
}

O parâmetro definido na etapa anterior funciona como uma variável declarada com a palavra-chave val. O valor dela pode ser usado em qualquer lugar na função birthdayGreeting(). Em um codelab anterior, você aprendeu como inserir o valor de uma variável em uma string.

  1. Substitua Rover na string nameGreeting pelo símbolo $ seguido pelo parâmetro name.
fun birthdayGreeting(name: String): String {
    val nameGreeting = "Happy Birthday, $name!"
    val ageGreeting = "You are now 5 years old!"
    return "$nameGreeting\n$ageGreeting"
}
  1. Execute o código e observe o erro. Agora que você declarou o parâmetro name, é necessário transmitir uma String ao chamar birthdayGreeting(). Quando você chama uma função que usa um parâmetro, um argumento é transmitido para ela. O argumento é o valor transmitido, como "Rover".
No value passed for parameter 'name'
  1. Transmita "Rover" para a chamada birthdayGreeting() na main().
fun main() {
    println(birthdayGreeting("Rover"))
}
  1. Execute o código e observe a saída. O nome "Rover" vem do parâmetro name.
Happy Birthday, Rover!
You are now 5 years old!
  1. Como birthdayGreeting() recebe um parâmetro, é possível usar um outro nome além de Rover. Adicione outra chamada para birthdayGreeting() dentro da chamada para println(), transmitindo o argumento "Rex".
println(birthdayGreeting("Rover"))
println(birthdayGreeting("Rex"))
  1. Execute o código novamente e observe que a saída é diferente, dependendo do argumento transmitido para birthdayGreeting().
Happy Birthday, Rover!
You are now 5 years old!
Happy Birthday, Rex!
You are now 5 years old!

5. Funções com vários parâmetros

Você já adicionou um parâmetro para mudar os parabéns com base no nome. Também é possível definir mais de um parâmetro para uma função, até mesmo parâmetros de tipos de dados diferentes. Nesta seção, você vai mudar os parabéns para que também mudem de acordo com a idade do cachorro.

Função com vários parâmetros

As definições dos parâmetros são separadas por vírgulas. Da mesma maneira, ao chamar uma função com vários parâmetros, você também separa os argumentos transmitidos com vírgulas. Vamos ver tudo isso em ação.

  1. Depois do parâmetro name, adicione um age do tipo Int à função birthdayGreeting(). A nova declaração da função precisa ter os dois parâmetros, name e age, separados por uma vírgula:
fun birthdayGreeting(name: String, age: Int): String {
    val nameGreeting = "Happy Birthday, $name!"
    val ageGreeting = "You are now 5 years old!"
    return "$nameGreeting\n$ageGreeting"
}
  1. A nova string de parabéns precisa usar o parâmetro age. Atualize a função birthdayGreeting() para usar o valor do parâmetro age na string ageGreeting.
fun birthdayGreeting(name: String, age: Int): String {
    val nameGreeting = "Happy Birthday, $name!"
    val ageGreeting = "You are now $age years old!"
    return "$nameGreeting\n$ageGreeting"
}
  1. Execute a função e observe os erros na saída:
No value passed for parameter 'age'
No value passed for parameter 'age'
  1. Modifique as duas chamadas para a função birthdayGreeting() na main() para transmitir uma idade diferente para cada cachorro. Transmita 5 para a idade do Rover e 2 para a idade do Rex.
fun main() {
    println(birthdayGreeting("Rover", 5))
    println(birthdayGreeting("Rex", 2))
}
  1. Execute o código. Agora que você transmitiu valores para ambos os parâmetros, a saída precisa refletir o nome e a idade de cada cachorro ao chamar a função.
Happy Birthday, Rover!
You are now 5 years old!
Happy Birthday, Rex!
You are now 2 years old!

Assinatura da função

Até agora, você aprendeu como definir o nome, as entradas (parâmetros) e as saídas da função. O nome da função com as entradas (parâmetros) é conhecido coletivamente como a assinatura da função. A assinatura da função consiste em tudo que vem antes do tipo de retorno e é mostrada no snippet de código abaixo.

fun birthdayGreeting(name: String, age: Int)

Os parâmetros separados por vírgulas, às vezes, são chamados de lista de parâmetros.

Muitas vezes, você vai encontrar esses termos na documentação de códigos criados por outros desenvolvedores. A assinatura da função informa o nome da função e os tipos de dados que podem ser transmitidos.

Você aprendeu várias novas sintaxes para definir funções. O diagrama abaixo mostra um resumo da sintaxe de funções.

Diagrama para recapitular a sintaxe da função

6. Argumentos nomeados

Nos exemplos anteriores, não era necessário especificar os nomes dos parâmetros, name ou age, ao chamar uma função. No entanto, você pode fazer isso se preferir. Por exemplo, você pode chamar uma função com vários parâmetros ou transmitir os argumentos em uma ordem diferente, como colocar o parâmetro age antes do name. Se você incluir o nome do parâmetro ao chamar a função, ele será um argumento nomeado (link em inglês). Tente usar um argumento nomeado com a função birthdayGreeting().

  1. Modifique a chamada para o Rex usando argumentos nomeados, conforme mostrado neste snippet de código. Para fazer isso, inclua o nome do parâmetro seguido de um sinal de igual e, em seguida, o valor (por exemplo, name = "Rex").
println(birthdayGreeting(name = "Rex", age = 2))
  1. Execute o código e observe que a saída se mantém inalterada:
Happy Birthday, Rover!
You are now 5 years old!
Happy Birthday, Rex!
You are now 2 years old!
  1. Reorganize os argumentos nomeados. Por exemplo, coloque o argumento nomeado age antes do name.
println(birthdayGreeting(age = 2, name = "Rex"))
  1. Execute o código e observe que a saída permanece a mesma. Mesmo que você tenha mudado a ordem dos argumentos, os mesmos valores são transmitidos para os mesmos parâmetros.
Happy Birthday, Rover!
You are now 5 years old!
Happy Birthday, Rex!
You are now 2 years old!

7. Argumentos padrão

Os parâmetros de função também podem especificar argumentos padrão. Talvez o Rover seja seu cachorro favorito, ou você espera que uma função seja chamada com argumentos específicos na maioria dos casos. Ao chamar uma função, você pode omitir argumentos para os quais há um padrão. Nesse caso, o padrão vai ser usado.

Para adicionar um argumento padrão, coloque o operador de atribuição (=) após o tipo de dado do parâmetro e o defina como um valor. Modifique seu código para usar um argumento padrão.

  1. Na função birthdayGreeting(), defina o parâmetro name com o valor padrão "Rover".
fun birthdayGreeting(name: String = "Rover", age: Int): String {
    return "Happy Birthday, $name! You are now $age years old!"
}
  1. Na primeira chamada para birthdayGreeting() para o Rover na main(), defina o argumento chamado age como 5. Como o parâmetro age é definido depois do name, você precisa usar o argumento nomeado age. Sem os argumentos nomeados, o Kotlin presume que a ordem dos argumentos seja a mesma em que os parâmetros são definidos. O argumento nomeado é usado para garantir que o Kotlin esteja esperando um valor Int para o parâmetro age.
println(birthdayGreeting(age = 5))
println(birthdayGreeting("Rex", 2))
  1. Execute o código. A primeira chamada para a função birthdayGreeting() mostra "Rover" como o nome, porque você não especificou o nome. A segunda chamada para birthdayGreeting() ainda usa o valor Rex, que você transmitiu para o name.
Happy Birthday, Rover! You are now 5 years old!
Happy Birthday, Rex! You are now 2 years old!
  1. Remova o nome da segunda chamada para a função birthdayGreeting(). Novamente, como o name é omitido, é necessário usar um argumento nomeado para a idade.
println(birthdayGreeting(age = 5))
println(birthdayGreeting(age = 2))
  1. Execute o código e observe que agora as duas chamadas para birthdayGreeting() mostram "Rover" como o nome, porque nenhum argumento nomeado foi transmitido.
Happy Birthday, Rover! You are now 5 years old!
Happy Birthday, Rover! You are now 2 years old!

8. Conclusão

Parabéns! Você aprendeu a definir e chamar funções no Kotlin.

Resumo

  • As funções são definidas usando a palavra-chave fun e contém partes de código reutilizáveis.
  • As funções facilitam a manutenção de programas maiores e evitam a repetição desnecessária de código.
  • As funções podem retornar um valor que pode ser armazenado em uma variável para uso futuro.
  • As funções podem ter parâmetros, que são variáveis disponíveis no corpo da função.
  • Argumentos são os valores que você transmite quando chama uma função.
  • Você pode nomear argumentos ao chamar uma função. Ao usar argumentos nomeados, é possível reordenar os argumentos sem afetar a saída.
  • É possível especificar um argumento padrão para omitir o argumento ao chamar uma função.