Baixar o código: LearnKotlin.kt
Kotlin é uma linguagem de programação estaticamente tipada para a JVM, Android e navegadores web. Ela é 100% interoperável com Java. Leia mais aqui.
// Comentários de uma linha iniciam com //
/*
Comentários multilinha se parecem com este.
*/
// A palavra-chave "package" funciona do mesmo modo que no Java.
package com.learnxinyminutes.kotlin
/*
O ponto de entrada para um programa em Kotlin é uma função chamada "main"
Esta função recebe um vetor contendo quaisquer argumentos da linha de comando
*/
fun main(args: Array<String>) {
/*
A declaração de valores pode ser feita tanto com "var" como "val"
Declarações com "val" não podem ser reatribuídas, enquanto com "var" podem.
*/
val umVal = 10 // não se poderá reatribuir qualquer coisa a umVal
var umVar = 10
umVar = 20 // umVar pode ser reatribuída, mas respeitando o tipo
/*
Na maioria dos casos Kotlin pode inferir o tipo, então não é preciso sempre
especificar o tipo explicitamente, mas quando o fazemos é assim:
*/
val umInteiro: Int = 7
/*
Strings podem ser representadas de forma semelhante a Java.
A contrabarra realiza o "escape", da mesma forma.
*/
val umaString = "Minha String está aqui!"
val outraString = "Imprimir na outra linha?\nSem problema!"
val maisString = "Você quer adicionar um tab?\tSem problema!"
println(umaString)
println(outraString)
println(maisString)
/*
Uma string bruta é delimitada com três aspas (""").
Strings brutas podem conter novas linhas e outros caracteres.
*/
val umaStringBruta = """
fun olaMundo(val nome : String) {
println("Olá, mundo!")
}
"""
println(umaStringBruta)
/*
As strings podem conter expressões modelo (template).
Uma expressão modelo começa com um cifrão ($).
É semelhante à interpolação de Strings em Ruby.
*/
val umaStringModelo = "$umaString tem ${umaString.length} caracteres"
println(umaStringModelo)
/*
Para uma variável receber null deve-se explicitamente declará-la
como anulável.
A declaração de anulável é realizada incluindo uma "?" ao fim do tipo.
Pode-se acessar uma variável anulável usando o operador "?."
Usa-se o operador "?:" (também conhecido como operador Elvis) para
atribuir um valor alternativo para quando uma variável é nula.
*/
var umaVariavelAnulavel: String? = "abc"
println(umaVariavelAnulavel?.length) // => 3
println(umaVariavelAnulavel?.length ?: -1) // => 3
umaVariavelAnulavel = null
println(umaVariavelAnulavel?.length) // => null
println(umaVariavelAnulavel?.length ?: -1) // => -1
/*
Funções podem ser declaradas usando a palavra-chave "fun"
Os parâmetros da função são declarados entre parênteses logo
após o nome da função.
Os parâmetros da função podem ter opcionalmente um valor padrão.
O tipo de retorno da função, se necessário, é especificado após os argumentos.
*/
fun ola(nome: String = "mundo"): String {
return "Olá, $nome!"
}
println(ola("você")) // => Olá, você!
println(ola(nome = "tu")) // => Olá, tu!
println(ola()) // => Olá, mundo!
/*
Um parâmetro pode ser declarado com a palavra-chave "vararg" para
permitir que seja passado um número variável de argumentos.
*/
fun exemploVarArg(vararg numeros: Int) {
println("Foram recebidos ${numeros.size} argumentos")
}
exemploVarArg() // => Passando nenhum argumento (0 argumentos)
exemploVarArg(1) // => Passando 1 argumento
exemploVarArg(1, 2, 3) // => Passando 3 argumentos
/*
Quando uma função consiste numa única expressão as chaves
podem ser omitidas e o corpo declarado após o símbolo de "="
*/
fun impar(x: Int): Boolean = x % 2 == 1
println(impar(6)) // => false
println(impar(7)) // => true
// O tipo de retorno não precisa ser declarado se pode ser inferido.
fun impar(x: Int) = x % 2 == 0
println(impar(6)) // => true
println(impar(7)) // => false
// Funções podem receber e retornar outras funções
fun nao(f: (Int) -> Boolean): (Int) -> Boolean {
return {n -> !f.invoke(n)}
}
// Funções nomeadas podem ser passadas como argumento usando o operador "::"
val naoImpar = nao(::impar)
val naoPar = nao(::par)
// Expressões Lambda podem ser usadas como argumentos
val naoZero = nao {n -> n == 0}
/*
Se uma lambda têm apenas um parâmetro sua declaração pode ser omitida,
incluindo o símbolo "->".
Neste caso o nome do único parâmetro deve ser "it".
*/
val naoPositivo = nao {it > 0}
for (i in 0..4) {
println("${naoImpar(i)} ${naoPar(i)} ${naoZero(i)} ${naoPositivo(i)}")
}
// A palavra-chave "class" é usada para declarar classes
class ClasseExemplo(val x: Int) {
fun funcaoMembro(y: Int): Int { // ou "método"
return x + y
}
infix fun funcaoMembroInfixa(y: Int): Int {
return x * y
}
}
/*
Para criar uma nova instância chama-se o construtor.
Note que Kotlin não tem a palavra-chave "new".
*/
val umaInstanciaDaClasseExemplo = ClasseExemplo(7)
// Funções membro (métodos) podem ser chamados usando a notação ponto "."
println(umaInstanciaDaClasseExemplo.funcaoMembro(4)) // => 11
/*
Se uma função foi declarada com a palavra-chave "infix" então
ela pode ser invocada com a notação infixa.
*/
println(umaInstanciaDaClasseExemplo funcaoMembroInfixa 4) // => 28
/*
Classes de dados são um modo sucinto de criar classes que servem apenas
para guardar informações.
Os métodos "hashCode", "equals" e "toString" são gerados automaticamente.
*/
data class ExemploClasseDados (val x: Int, val y: Int, val z: Int)
val objetoDados = ExemploClasseDados(1, 2, 4)
println(objetoDados) // => ExemploClasseDados(x=1, y=2, z=4)
// Classes de dados têm uma função "copy"
val dadosCopia = objetoDados.copy(y = 100)
println(dadosCopia) // => ExemploClasseDados(x=1, y=100, z=4)
// Objetos podem ser desestruturados em múltiplas variáveis.
val (a, b, c) = dadosCopia
println("$a $b $c") // => 1 100 4
// desestruturando em um laço "for"
for ((a, b, c) in listOf(objetoDados)) {
println("$a $b $c") // => 1 100 4
}
val mapaDados = mapOf("a" to 1, "b" to 2)
// Map.Entry também é desestruturável
for ((chave, valor) in mapaDados) {
println("$chave -> $valor")
}
// A função "with" é semelhante à declaração "with" do JavaScript
data class ExemploClasseDadosMutaveis (var x: Int, var y: Int, var z: Int)
val objDadosMutaveis = ExemploClasseDadosMutaveis(7, 4, 9)
with (objDadosMutaveis) {
x -= 2
y += 2
z--
}
println(objDadosMutaveis) // => ExemploClasseDadosMutaveis(x=5, y=6, z=8)
/*
Pode-se criar uma lista usando a função "listOf".
A lista é imutável, isto é, elementos não podem ser adicionados ou removidos.
*/
val umaLista = listOf("a", "b", "c")
println(umaLista.size) // => 3
println(umaLista.first()) // => a
println(umaLista.last()) // => c
// Elementos de uma lista podem ser acessados pelo índice
println(umaLista[1]) // => b
// Uma lista mutável pode ser criada com a função "mutableListOf".
val umaListaMutavel = mutableListOf("a", "b", "c")
umaListaMutavel.add("d")
println(umaListaMutavel.last()) // => d
println(umaListaMutavel.size) // => 4
// Similarmente, pode-se criar um conjunto com a função "setOf".
val umConjunto = setOf("a", "b", "c")
println(umConjunto.contains("a")) // => true
println(umConjunto.contains("z")) // => false
// Da mesma forma que um mapa com a função "mapOf".
val umMapa = mapOf("a" to 8, "b" to 7, "c" to 9)
// Os valores contidos no mapa podem ser acessados pela sua chave.
println(umMapa["a"]) // => 8
/*
Sequências representam coleções avaliadas "preguiçosamente" (sob demanda).
Pode-se criar uma sequência usando a função "generateSequence".
*/
val umaSequencia = generateSequence(1, { it + 1 })
val x = umaSequencia.take(10).toList()
println(x) // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// Um exemplo de uma sequência usada para gerar Números de Fibonacci:
fun sequenciaFibonacci(): Sequence<Long> {
var a = 0L
var b = 1L
fun proximo(): Long {
val resultado = a + b
a = b
b = resultado
return a
}
return generateSequence(::proximo)
}
val y = sequenciaFibonacci().take(10).toList()
println(y) // => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
// Kotlin oferece funções de alta-ordem para trabalhar com coleções.
val z = (1..9).map {it * 3}
.filter {it < 20}
.groupBy {it % 2 == 0}
.mapKeys {if (it.key) "par" else "impar"}
println(z) // => {impar=[3, 9, 15], par=[6, 12, 18]}
// Um "for" pode ser usado com qualquer coisa que ofereça um "iterator"
for (c in "salve") {
println(c)
}
// O "while" funciona da mesma forma que em outras linguagens.
var contador = 0
while (contador < 5) {
println(contador)
contador++
}
do {
println(contador)
contador++
} while (contador < 10)
/*
"if" pode ser usado como uma expressão que retorna um valor.
Por este motivo o operador ternário "? :" não é necessário em Kotlin.
*/
val numero = 5
val mensagem = if (numero % 2 == 0) "par" else "impar"
println("$numero é $mensagem") // => 5 é impar
// "when" pode ser usado como alternativa às correntes de "if-else if".
val i = 10
when {
i < 7 -> println("primeiro block")
umaString.startsWith("oi") -> println("segundo block")
else -> println("bloco else")
}
// "when" pode ser usado com um argumento.
when (i) {
0, 21 -> println("0 ou 21")
in 1..20 -> println("entre 1 e 20")
else -> println("nenhum dos anteriores")
}
// "when" pode ser usada como uma função que retorna um valor.
var resultado = when (i) {
0, 21 -> "0 ou 21"
in 1..20 -> "entre 1 e 20"
else -> "nenhum dos anteriores"
}
println(resultado)
/*
Pode-se verificar se um objeto é de um certo tipo usando o operador "is".
Se o objeto passar pela verificação então ele pode ser usado como
este tipo, sem a necessidade de uma coerção (cast) explícita (SmartCast).
*/
fun exemploSmartCast(x: Any) : Boolean {
if (x is Boolean) {
// x é automaticamente coagido para Boolean
return x
} else if (x is Int) {
// x é automaticamente coagido para Int
return x > 0
} else if (x is String) {
// x é automaticamente coagido para String
return x.isNotEmpty()
} else {
return false
}
}
println(exemploSmartCast("Olá, mundo!")) // => true
println(exemploSmartCast("")) // => false
println(exemploSmartCast(5)) // => true
println(exemploSmartCast(0)) // => false
println(exemploSmartCast(true)) // => true
// O Smartcast também funciona com blocos "when"
fun exemploSmartCastComWhen(x: Any) = when (x) {
is Boolean -> x
is Int -> x > 0
is String -> x.isNotEmpty()
else -> false
}
/*
As extensões são uma maneira nova de adicionar funcionalidades a classes.
Elas são similares aos "extension methods" da linguagem C#.
*/
fun String.remove(c: Char): String {
return this.filter {it != c}
}
println("olá, mundo!".remove('o')) // => lá, mund!
println(ExemploEnum.A) // => A
println(ExemploObjeto.ola()) // => olá
}
// Classes Enum são similares aos "enum types" do Java.
enum class ExemploEnum {
A, B, C
}
/*
A palavra-chave "object" pode ser usar para criar Singletons.
Eles não são instanciados, mas podem referenciar sua instância única pelo nome.
É semelhante aos "singleton objects" da linguagem Scala.
*/
object ExemploObjeto {
fun ola(): String {
return "olá"
}
}
fun usaObjeto() {
ExemploObjeto.ola()
val algumaReferencia: Any = ExemploObjeto // usa-se o nome diretamente
}
Sugestões ou correções? Abra uma issue no repositório do GitHub, ou faça um pull request você mesmo!
Originalmente contribuído por S Webber e atualizado por 3 colaboradores.