Você está na página 1de 100

Machine Translated by Google

Machine Translated by Google

Programando Kotlin
Criando elegante, expressivo e de alto desempenho
Aplicativos JVM e Android

por Venkat Subramaniam

Versão: P1.0 (setembro de 2019)


Machine Translated by Google

Copyright © 2019 The Pragmatic Programmers, LLC. Este livro é licenciado para o indivíduo que o comprou. Não o
protegemos contra cópia porque isso limitaria sua capacidade de usá-lo para seus próprios fins. Por favor, não
quebre essa confiança – você pode usar isso em todos os seus dispositivos, mas não compartilhe esta cópia com
outros membros da sua equipe, com amigos ou por meio de serviços de compartilhamento de arquivos. Obrigado.

Muitas das designações utilizadas pelos fabricantes e vendedores para distinguir os seus produtos são reivindicadas como
marcas comerciais. Onde essas designações aparecem neste livro, e a The Pragmatic Programmers, LLC estava ciente
de uma reivindicação de marca registrada, as designações foram impressas em letras maiúsculas ou em letras maiúsculas.
The Pragmatic Starter Kit, The Pragmatic Programmer, Pragmatic Programming, Pragmatic Bookshelf e o dispositivo g de
ligação são marcas registradas de The Pragmatic Programmers, LLC.

Todas as precauções foram tomadas na preparação deste livro. No entanto, o editor não assume nenhuma
responsabilidade por erros ou omissões, ou por danos que possam resultar do uso das informações (incluindo
listagens de programas) aqui contidas.

Sobre a estante pragmática


A Pragmatic Bookshelf é uma editora ágil. Estamos aqui porque queremos melhorar a vida dos desenvolvedores. Fazemos
isso criando títulos práticos e oportunos, escritos por programadores para
programadores.

Nossos cursos, workshops e outros produtos Pragmatic podem ajudar você e sua equipe a criar softwares
melhores e a se divertir mais. Para obter mais informações, bem como os títulos mais recentes da Pragmatic, visite-nos
em http://pragprog.com.

Nossos e-books não contêm nenhum gerenciamento de restrições digitais e sempre foram livres de DRM. Fomos pioneiros
no conceito de livro beta, onde você pode comprar e ler um livro enquanto ele ainda está sendo escrito e fornecer feedback
ao autor para ajudar a criar um livro melhor para todos. Recursos gratuitos para todos os compradores incluem
downloads de código-fonte (se aplicável), erratas e fóruns de discussão, todos disponíveis na página inicial do livro em
pragprog.com. Estamos aqui para facilitar sua vida.

Anúncios de novos livros

Quer ficar por dentro de nossos títulos e anúncios mais recentes e ofertas especiais ocasionais? Basta criar uma conta
em pragprog.com (basta um endereço de e-mail e uma senha) e marque a caixa de seleção para receber boletins
informativos. Você também pode nos seguir no Twitter como @pragprog.

Sobre formatos de e-book

Se você comprar diretamente de pragprog.com, você obtém e-books em todos os formatos disponíveis por um preço
único. Você pode sincronizar seus e-books entre todos os seus dispositivos (incluindo iPhone/iPad, Android,
laptops, etc.) via Dropbox. Você recebe atualizações gratuitas durante toda a vida da edição. E, claro, você sempre pode
voltar e baixar novamente seus livros quando necessário. Os e-books comprados na loja Kindle da Amazon estão
sujeitos às políticas da Amazon. As limitações no formato de arquivo da Amazon podem fazer com que os e-books
sejam exibidos de maneira diferente em dispositivos diferentes. Para obter mais informações, consulte nosso
FAQ em pragprog.com/frequently-asked-questions/ebooks. Para saber mais sobre este livro e
acessar os recursos gratuitos, acesse https://pragprog.com/book/vskotlin, a página inicial do livro.

Obrigado pelo seu apoio contínuo,

Andy Hunt
Os programadores pragmáticos

A equipe que produziu este livro inclui: Andy Hunt (Editor),


Janet Furlow (VP de Operações), Susan Conant (Editora Gerente),
Jacquelyn Carter (editora de desenvolvimento), Sakhi MacMillan (editora de texto),
Potomac Indexing, LLC (Indexação), Gilson Graphics (Layout)

Para suporte ao cliente, entre em contato com support@pragprog.com.

Para direitos internacionais, entre em contato com rights@pragprog.com.


Machine Translated by Google

Índice

Prefácio

Agradecimentos

Introdução
Para quem é este livro?

O que há neste livro?

Versões Kotlin e Java usadas neste livro

Como ler os exemplos de código


Recursos online

1. Olá Kotlin
Razões para amar Kotlin

Por que você deve escolher Kotlin?

Levando Kotlin para um

passeio Compile para Bytecode e

execute a compilação para

outros destinos Qual opção escolher?

Empacotando

Parte I. Scripts com Kotlin

2. Kotlin Essentials para Java Eyes


Machine Translated by Google

Menos digitação

Avisos sensatos
Prefira val a var

Verificação de igualdade aprimorada

Modelos de string

Cordas brutas

Mais expressões, menos declarações

Empacotando

3. Trabalhando com Funções


Criando Funções

Argumentos padrão e nomeados

vararg e spread

Desestruturação

Empacotando

4. Iteração externa e intervalo de correspondência de argumentos e

iteração de iteração

sobre matrizes e listas


Quando é hora de usar quando

Empacotando

5. Usando coleções
Sabores de Coleções

Usando Par e Triplo

Matrizes de objetos e primitivos

Usando lista

Usando Conjunto

Usando Mapa
Machine Translated by Google

Empacotando

6. Digite Segurança para Salvar o Dia Aulas

de Qualquer e Nada
Referências anuláveis

Verificação e conversão de tipo

Casting de tipo explícito

Genéricos: Variância e Restrições de Tipos Paramétricos

Parâmetros de tipo reificado

Empacotando

Parte II. Kotlin Orientado a Objetos

7. Objetos e Classes Objetos e

Singletons Criando Classes

Objetos

Companheiros e Membros de Classe Criando

Classes Genéricas
Classes de dados

Empacotando

8. Hierarquias e herança de classe

Criando Interfaces e Classes Abstratas


Classes aninhadas e internas

Herança

Aulas Seladas

Criando e usando Enums

Empacotando
Machine Translated by Google

9. Extensão através de delegação


Quando escolher a delegação em vez da herança?
Projetando com Delegados

Delegando a um Parâmetro

Lidando com Colisões de Métodos

Advertências da Delegação Kotlin

Delegando Variáveis e Propriedades

Delegados Padrão Integrados

Conclusão

Parte III. Kotlin funcional

10. Programação Funcional com Lambdas


O estilo funcional

Expressões Lambda

Lambdas e funções anônimas

Fechamentos e escopo lexical


Devolução não local e etiquetada

Funções embutidas com Lambdas

Empacotando

11. Iteração interna e avaliação preguiçosa


Iteradores externos vs. internos

Iteradores Internos

Sequências para avaliação preguiçosa

Empacotando
Machine Translated by Google

Parte IV. Kotlin elegante e eficiente

12. Fluência em Kotlin


Sobrecarregando Operadores

Injetando usando funções e propriedades de extensão

Estendendo Funções

Fluência de função com infix

Fluência com Qualquer Objeto

Receptores Implícitos

Empacotando

13. Criando DSLs Internas


Tipos e características de DSLs
Kotlin para DSLs internas

Desafios na construção da fluência

Construtores de tipo seguro

Restringindo o acesso com controle de escopo

Empacotando

14. Programação de recursão e memorização


O poder e os perigos da recursão

Otimização de chamada final


Memoização

Aplicando Memoização à Programação Dinâmica

Empacotando
Machine Translated by Google

Parte V. Programação de aplicativos assíncronos

15. Explorando corrotinas


Corrotinas e simultaneidade
em execução simultânea usando corrotinas
Contexto e threads da corrotina

Depurando corrotinas

assíncronas e aguardando
Uma espiada nas continuações

Criando sequências infinitas

Empacotando

16. Programação Assíncrona


Programação Tratamento
Assíncrono de Exceções
Cancelamentos e tempos limite

Empacotando

Parte VI. Interoperabilidade e testes

17. Misturando compilação conjunta


de Java e Kotlin
Chamando Java de
Kotlin Chamando Kotlin
de Java Conclusão
Machine Translated by Google

18. Teste de unidade com Kotlin


O código em teste

Obtendo os arquivos do projeto

Começando com um teste canário

Escrevendo testes empíricos

Escrevendo testes baseados em dados

Zombando Dependências

Testando funções de nível superior

Testando corrotinas e chamadas assíncronas

Integrando com o serviço

Visualizando a cobertura do código

Levando o aplicativo para um passeio

Empacotando

19. Programando aplicativos Spring com Kotlin


Criando um projeto inicial

Criando um controlador

Criando uma classe de entidade

Criando uma interface de repositório

Criando um serviço

Integrando o serviço com o controlador

Levando para um passeio

Empacotando

20. Escrevendo aplicativos Android com Kotlin


Criando um
projeto Definindo objetos
de domínio Criando layouts
Machine Translated by Google

Implementando a Atividade
Atualizando o RecyclerView
Vendo o aplicativo em ação
Empacotando

A1. Transpilando para JavaScript

A2. Kotlin/nativo

A3. Kotlin para WebAssembly

Bibliografia

Copyright © 2020, The Pragmatic Bookshelf.


Machine Translated by Google

Elogios iniciais à programação


Kotlin
Venkat é alguém que pode abordar qualquer assunto e torná-lo prazeroso e fácil de entender.
Neste livro ele irá levá-lo em uma aventura de aprender Kotlin de uma forma clara e
pragmática, fornecendo usos no mundo real e, ao mesmo tempo, mostrando os benefícios da
linguagem.

ÿHadi Hariri

Advogado do desenvolvedor, JetBrains

Este livro abrirá as portas para o incrível mundo de Kotlin. Você será guiado ao longo
desta jornada por um dos mais famosos oradores e educadores de nossos dias. Tenha um
bom Kotlin!

ÿ Eugene Petrenko, PhD


Desenvolvedor, Palestrante, JetBrains

Entre na caverna de Kotlin usando este excelente livro como farol. Ganhe confiança nesta
bela linguagem enquanto um explorador de cavernas ganha autoconfiança ao encontrar seu
caminho em uma caverna recém-explorada nunca antes vista pelos olhos humanos. Explore
pragmaticamente cada vez mais profundamente esta linguagem JVM moderna usando o
conhecimento, dicas e diretrizes fornecidas por um entusiasta extraordinário e
experiente em linguagem de programação: Venkat.

ÿTom Adam

Consultor sênior, CEO, Lambda Consulting AS

A maneira envolvente e bem-humorada de explicar as coisas, como Venkat faz em suas palestras, também é

exibida neste livro. É um guia muito bem estruturado e de fácil leitura para todos que estão — ou desejam

começar — a programar em Kotlin.


Machine Translated by Google

ÿBrian Vermeer

Advogado do desenvolvedor, Snyk

Realmente um livro perfeito para começar a trabalhar, e não apenas ouvir sobre o
hype do Kotlin. Na verdade, isso explicou qual é o burburinho sobre Kotlin. Venkat fez
isso mais uma vez! Um livro de leitura obrigatória, não apenas para começar a usar
Kotlin, mas também para comparar o que está faltando em Java.

ÿ Zulfikar Dharmawan

Engenheiro de software, ING Bank NV

Kotlin é uma nova linguagem muito promissora, e Venkat usa seu conhecimento, humor
e clara admiração por Kotlin para criar um livro muito legível e educativo. Venkat
explica as coisas muito bem, dá conselhos úteis e até dá risadas ocasionais.

ÿTory Zundel
Arquiteto de software

O livro é bem elaborado com exemplos bons e sucintos – altamente


recomendado para desenvolvedores Java que desejam fazer a transição para Kotlin.

ÿ Ashish Bhatia

Engenheiro de software e blogueiro, ashishb.net

Se você está satisfeito com Java e não vê necessidade de travessia segura para nulos
ou delegação de primeira classe, então largue este livro; você não está pronto. Caso
contrário, leia este livro. Você será entretido e educado simultaneamente.

ÿ Daniel DeGroff
CTO, FusionAuth
Machine Translated by Google

Prefácio
Com este livro, você aprenderá Kotlin. Em nome da equipe Kotlin eu digo: seja bem vindo!

Em 2010, quando iniciamos o Kotlin, pensamos nele como uma ferramenta para
desenvolvedores Java, permitindo que eles construíssem o que quisessem com facilidade e
prazer. Apostamos na segurança de tipo para excelente ferramental e detecção precoce de
erros de programação. Apostamos na interoperabilidade com Java para dar a todos os
desenvolvedores Kotlin acesso ao vasto ecossistema Java. Hoje em dia, Kotlin é uma
linguagem multiplataforma que pode rodar em um servidor rodando JVM, em um dispositivo
Android, em um navegador web, em um dispositivo iOS ou em uma máquina
Linux ou até mesmo em um microcontrolador. Mesmo assim, nossos princípios permaneceram
os mesmos: permitimos que as pessoas construíssem software com facilidade e prazer e
apostamos em ferramentas, interoperabilidade com todas as plataformas e na detecção precoce de erros.

O desenvolvimento da linguagem tem vários estágios. Primeiro você só tem uma ideia, e nessa
fase eu estava cheio de dúvidas e ao mesmo tempo com muita vontade de experimentar.
Pode-se chamar isso de fé, talvez. Então você tem seu primeiro programa compilado e
executado. Está começando a tomar forma. Então cresce. Então você resolve muitos problemas.
E mais problemas. Então, se você tiver sorte, alguém de fora da sua equipe ficará entusiasmado
com o seu idioma e você estará no paraíso. Os primeiros usuários vêm e fornecem feedback.
Depois, mais problemas e muitas dúvidas: estamos prontos para lançar? Então você
simplesmente não pode esperar mais, você dobra e lança 1.0. Você comemora brevemente
e corre para corrigir todos os problemas relatados pelos novos usuários. O tempo passa, o
ecossistema cresce, a equipe cresce, mais usuários, algumas novidades, novos lançamentos,
mais
Machine Translated by Google

bugs, as pessoas escrevem projetos maiores… Aí um autor que já era conhecido


antes mesmo de você começar escreve um livro sobre o seu idioma. Eu estou aqui. É
uma sensação boa :).

Como este livro pressupõe algum conhecimento de Java, você começará onde
começamos e, quando chegar ao final do livro, terá uma visão muito boa da
linguagem e de suas aplicações práticas no mundo JVM e no Android. Você saberá
como fazer o que quiser com Kotlin e como ele pode ajudá-lo. Meu objetivo como
designer de linguagem é tornar o Kotlin útil para você, e Venkat fez um ótimo trabalho
ao tornar seu aprendizado agradável.

Desejo-lhe um bom tempo com este livro. Tenha um bom Kotlin!

Andrei Breslav

Designer-chefe do Kotlin

Julho, 2019

Copyright © 2020, The Pragmatic Bookshelf.


Machine Translated by Google

Agradecimentos
Gostaria de expressar meu mais profundo respeito e gratidão à equipe Kotlin, aos
desenvolvedores da JetBrains que estão trabalhando incansavelmente em diferentes
partes da linguagem e ferramentas relacionadas. Sempre soube que eles eram muito
inteligentes, mas uma breve visita com eles me mostrou também o quão receptivos,
interessados e meticulosos eles são em aprender sobre o uso da língua na natureza,
para que possam aprimorá-la. Obrigado, equipe, continuem com seu trabalho duro; o
que você faz é sinceramente apreciado.

Vários desenvolvedores que revisaram este livro me mostraram muitas maneiras


pelas quais eu deveria melhorar. Eles me ensinaram sobre os casos extremos que
eu havia perdido, compartilharam suas experiências e me deram dicas úteis. Este livro
é melhor por causa da excelente crítica de Tom Adam, Ashish Bhatia, Andrey
Breslav, Daniel DeGroff, Zulfikar Dharmawan, Roman Elizarov, Hadi Hariri, Steven
Hicks, Rod Hilton, Ragunath Jawahar, Manuel Jordan, Dave Klein, Josh Long, Ted
Neward, Eugene Petrenko, Owen Rumney, Nate Schutta, Brian Vermeer, Brian
Sletten, Craig Walls e Tory Zundel.
Em particular, gostaria de fazer uma menção especial às extensas e completas
resenhas de Tom Adam e Eugene Petrenko — estou muito feliz por tê-los
convidado para resenhar este livro e estou grato por vocês dois terem aceitado.

Um dos bons benefícios de lançar um livro em versões beta, disponibilizando o


conteúdo para os leitores enquanto ele ainda está sendo escrito, é o feedback dos
primeiros leitores através da página de erratas do livro. Gostaria de agradecer a
Cassian Braconnier, Pere Casafont, Freek de Bruijn, Nicholas Erasmus, Bill
Judd, Daniel Kay, Jacques Ledoux, Michiel Leegwater,
Machine Translated by Google

Adekunle Lukman, Ioannis Mavroukakis, Kin Pi, Paolo Pilloni, N.


Raghavendra, Mark Rotteveel, Felipe Sultani e Jeroen Wenting. O feedback que você
forneceu me ajudou a melhorar este livro em cada versão beta.

Cada página deste livro se beneficiou de análises extensas, múltiplas e altamente


pacientes de minha editora Jackie Carter. Ela estabeleceu um padrão muito alto sobre o
que esperar de um editor. Obrigado, Jackie, por tudo o que você faz, tanto nas
avaliações quanto em termos de apoio moral e incentivos que você forneceu,
especialmente quando as coisas não estavam indo bem. Tenho muito a aprender com
você.

Gostaria de agradecer ao pessoal da Pragmatic Bookshelf, Andy Hunt, Brian


MacDonald, Janet Furlow e muitos outros que trabalharam nos bastidores para tornar
este livro uma realidade. As respostas rápidas e a assistência de cada um de vocês
tornaram esta jornada muito prazerosa. Obrigado por aceitar este livro para
publicação.

Nada disso teria sido possível sem o apoio, incentivo e paciência da minha família. Sou
grato à minha esposa Kavitha e aos meus filhos Karthik e Krupa. Agora que terminei
este livro, deveria ter mais tempo para piadas de pai.

Copyright © 2020, The Pragmatic Bookshelf.


Machine Translated by Google

Introdução

Você pode dizer que as linguagens de programação me fascinam. Como entusiasta


de idiomas, codifico em cerca de quinze idiomas diferentes e escrevi livros sobre
alguns deles. Adoro idiomas, todos eles.

Aprender um idioma é como visitar uma cidade. Você encontra coisas novas, mas também
vê coisas que são comuns. O que é familiar traz conforto e as diferenças intrigam. Para
ter sucesso no aprendizado de um idioma, precisamos de um bom equilíbrio entre os dois.

Vários de nós aspiramos ser programadores poliglotas. Kotlin é em si uma


linguagem poliglota. Ele reúne recursos poderosos de muitos idiomas diferentes. Os
criadores do Kotlin pegaram as partes boas de várias linguagens e as combinaram em uma
linguagem altamente acessível e pragmática.

Quando comecei a aprender Kotlin minha mente estava em chamas, vendo os recursos
que gostei em diferentes linguagens como Java, Groovy, Scala, C++, C#, Ruby, Python,
JavaScript, Erlang, Haskell… Ao mesmo tempo, existem tantas nuances em Kotlin que me
tornaram muito mais produtivo em programação do que qualquer uma dessas
linguagens.

Algumas linguagens dizem como você deve escrever código. Kotlin não é um desses.
Com o Kotlin, você decide qual paradigma funciona melhor para o aplicativo
em questão. Por exemplo, você pode descobrir que o estilo imperativo é melhor em um
aplicativo grande porque você precisa lidar com efeitos colaterais e exceções
inerentes, e o Kotlin facilita a programação nesse estilo.
Machine Translated by Google

Mas, em outra parte do aplicativo, você pode precisar lidar com transformações
de big data, então você decide que o estilo funcional é melhor para isso, e o
Kotlin se transformará instantaneamente em uma charmosa linguagem de
programação funcional. Ao escrever código orientado a objetos, você verá que
o compilador funciona para você, em vez de você trabalhar para o compilador.

Você verá meu entusiasmo pelo idioma ao longo deste livro. Foi divertido
aprender e aplicar Kotlin. Espero que este livro torne sua jornada para aprender
o idioma agradável. Obrigado por atender.
Machine Translated by Google

Para quem é este livro?

Este livro é para programadores, desenvolvedores líderes, arquitetos e gerentes técnicos.


O livro pressupõe familiaridade com os fundamentos da programação e também conhecimento
moderado de Java e JDK. O livro não pressupõe nenhum conhecimento de Kotlin. Se
você é um programador Android, este livro estabelece a boa base necessária
para programar esses dispositivos com Kotlin, embora este livro não se concentre
exclusivamente na plataforma Android.

Se você é novo no Kotlin, este livro o ajudará a começar e avançar rapidamente com a
aplicação da linguagem em seus projetos. Se você já usa Kotlin, poderá usar este livro
para obter uma compreensão mais profunda de alguns dos recursos avançados da
linguagem.

Você também pode usar este livro para treinar seus desenvolvedores para se tornarem
proficientes em Kotlin, para usá-lo para criar código altamente fluente e expressivo e para
resolver problemas complexos.
Machine Translated by Google

O que há neste livro?

Kotlin é uma linguagem de programação multiparadigma. Você pode escrever scripts


simples em Kotlin, escrever código orientado a objetos, código de estilo funcional,
programar de forma assíncrona e muito mais. Para fornecer uma cobertura razoável a
esse amplo espectro de tópicos, este livro está dividido em várias partes.

A Parte I concentra-se na criação de scripts com Kotlin. A Parte II trata de programação


orientada a objetos. Na Parte III, você aprenderá a usar os recursos de estilo funcional da
linguagem. A Parte IV reunirá o que você aprendeu até agora para tornar seu código mais
fluente e ensinará como criar linguagens internas específicas de domínio (DSLs). Na Parte
V, você aprenderá sobre as novas corrotinas e a programação assíncrona. A Parte
VI final trata da interoperabilidade Java, testes, uso de Kotlin com Spring e programação
de aplicativos Android com Kotlin.

Aqui está o que é abordado em cada capítulo:

No Capítulo 1, Olá Kotlin, examinamos os motivos para usar Kotlin, baixamos as


ferramentas necessárias e começamos a escrever código.

Os programadores vindos do Java para o Kotlin têm algumas práticas e sintaxe para
desaprender antes de começarem a aprender o que há de novo e diferente no Kotlin.
Abordaremos isso no Capítulo 2, Kotlin Essentials for the Java Eyes.

As funções são cidadãs de primeira classe em Kotlin, e a linguagem tem muito a oferecer,
como argumentos padrão e nomeados e varargs. Explore esses recursos
relacionados a funções no Capítulo 3, Trabalhando com funções.

Ao programar no estilo imperativo, frequentemente usamos iteradores externos.


Você verá no Capítulo 4, Iteração externa e correspondência de argumentos, como
os iteradores do Kotlin tornam essa tarefa suportável e como a sintaxe de correspondência
de argumentos remove muito ruído das instruções condicionais.
Machine Translated by Google

Trabalhamos extensivamente com coleções durante a programação. O Capítulo 5, Usando


coleções, mostrará como usar interfaces de visualização para trabalhar com as
coleções JDK do Kotlin.

Kotlin tem um sistema de tipo de som e sua verificação de tipo em tempo de compilação
vai além do que esperamos de linguagens de tipo estaticamente. No Capítulo 6,
Segurança de tipo para salvar o dia, veremos os tipos fundamentais do Kotlin, referências
anuláveis e não anuláveis, conversões inteligentes, variação genérica e muito mais.

Embora semanticamente equivalente, criar classes em Kotlin é bem diferente do que em


Java. No Capítulo 7, Objetos e Classes, você aprenderá a criar singletons, classes,
objetos complementares e os motivos para usar classes de dados.

O tratamento da herança em Kotlin é muito diferente da maneira como é usado em Java.


As classes são finais por padrão e a linguagem estabelece algumas regras para
melhorar a segurança de tipo e as verificações em tempo de compilação. Exploraremos
esse tópico em profundidade no Capítulo 8, Hierarquias de classe e herança.

Como uma das linguagens que tem suporte direto para delegação, o Kotlin fornece
alguns delegados integrados e também facilita a criação de delegados personalizados.
Começaremos com uma discussão sobre quando e por que usar a delegação e depois nos
aprofundaremos no uso de delegados no Capítulo 9, Extensão por meio da
delegação.

No Capítulo 10, Programação Funcional com Lambdas, você aprenderá como criar
expressões lambda e como escrever funções de ordem superior. Também abordaremos
os recursos oferecidos em Kotlin para eliminar a sobrecarga de chamadas de função e

melhorar o desempenho.

Os iteradores internos oferecem fluência e as sequências nos dão eficiência. Aplicaremos


o estilo funcional para iterar e processar coleções de objetos no Capítulo 11, Iteração
interna e avaliação lenta.
Machine Translated by Google

O Capítulo 12, Fluência em Kotlin, mostrará muitos dos recursos do Kotlin para criar
código conciso, fluente, elegante e expressivo.

O Capítulo 13, Criando DSLs Internas, baseia-se no tópico de fluência para criar DSLs
internas, para definir sua própria sintaxe para sua linguagem especializada, mas com total
segurança de tipo em tempo de compilação.

Kotlin é uma das poucas linguagens na JVM que fornece otimização de chamada
final. Veremos isso em ação no Capítulo 14, Programando Recursão e
Memoização, junto com o uso da memoização para reduzir a complexidade
computacional.

As corrotinas são um recurso estável no Kotlin 1.3 e, junto com as continuações,


fornecem a infraestrutura fundamental para programação assíncrona.
Os princípios básicos de corrotinas e continuações são abordados no Capítulo 15,
Explorando corrotinas.

No Capítulo 16, Programação Assíncrona, você aplicará corrotinas para criar


aplicativos práticos que podem se beneficiar da execução assíncrona de programas.

Kotlin pode ser executado em diferentes plataformas, incluindo a Java Virtual Machine.
No Capítulo 17, Misturando Java e Kotlin, você aprenderá como misturar Kotlin com
Java; como usar Kotlin em versões modernas de Java — ou seja, com módulos Java;
como usá-lo com Maven e Gradle; e também como trabalhar perfeitamente com Java e
Kotlin no mesmo aplicativo.

Mesmo que o compilador Kotlin detecte vários erros, o teste automatizado é uma
prática essencial para o desenvolvimento ágil sustentável. Você aprenderá como criar
testes unitários e medir a cobertura de código no Capítulo 18, Testes unitários com
Kotlin.

No Capítulo 19, Programando aplicativos Spring com Kotlin, exploraremos as


bibliotecas Spring voltadas para programadores Kotlin e o exclusivo
Machine Translated by Google

capacidades que estes oferecem.

Finalmente, no Capítulo 20, Escrevendo aplicativos Android com Kotlin, usaremos Kotlin para criar um

aplicativo Android que se comunica com um serviço de back-end.


Machine Translated by Google

Versões Kotlin e Java usadas neste livro


Para executar os exemplos deste livro você deve ter Kotlin 1.3 e Java 1.6 ou
superior. Embora a maioria dos exemplos também funcione em versões anteriores
do Kotlin, alguns exemplos exigirão o Kotlin 1.3. Os exemplos no capítulo
Java Interop exigirão Java 9 ou posterior. Instruções para baixar as
ferramentas necessárias são fornecidas no próximo capítulo.
Machine Translated by Google

Como ler os exemplos de código


A maioria dos exemplos neste livro são escritos como script Kotlin para que você possa
executá-los facilmente como um único arquivo sem compilação explícita. Quando a
compilação e outras etapas forem necessárias, as instruções serão fornecidas junto com o código.

Para economizar espaço, a saída de um trecho de código é mostrada como uma linha de
comentário na mesma linha do comando println() sempre que possível ou na próxima linha.
Ocasionalmente, uma linha de comentário diz algo sobre o código em vez de mostrar o
resultado esperado.
Machine Translated by Google

Recursos online
Este livro tem uma página oficial[1] no site Pragmatic Bookshelf. A partir daí você pode
baixar todo o código-fonte de exemplo do livro. Você também pode fornecer comentários
enviando entradas de erratas.

Se estiver lendo o livro em formato PDF, você pode clicar no link acima de uma lista
de códigos para visualizar ou baixar os exemplos específicos.

Agora, divirta-se com Kotlin…

Notas de rodapé

[1]
http://www.pragprog.com/titles/vskotlin

Copyright © 2020, The Pragmatic Bookshelf.


Machine Translated by Google

Capítulo 1

Olá Kotlin
Ah, Kotlin – é uma ilha perto de São Petersburgo, na Rússia, mas este livro é sobre
sua linguagem de programação homônima. Os programadores que usam Kotlin não
gostam apenas da linguagem – eles dizem que a adoram. Quais são os motivos desse
carinho? Essa é a pergunta com a qual começaremos rapidamente. Em seguida, iremos
instalar o Kotlin Software Developer Kit (SDK), escrever algum código, compilá-lo e executá-
lo para que possamos vê-lo funcionando.

Imagine pegar o melhor de muitas linguagens diferentes – C++, C#, Erlang, Groovy,
Java, JavaScript, Python, Ruby, Scala, Smalltalk – jogá-las em um liquidificador e ligá-lo;
o coquetel resultante é Kotlin. A força do Kotlin está na sua diversidade.

Andrey Breslav[2] e a equipe de desenvolvedores por trás da linguagem da


JetBrains[3] decidiram criar uma linguagem fluente, expressiva, pragmática e fácil de usar,
que fosse menos detalhada do que muitas linguagens convencionais. À medida
que os programadores aprendem o Kotlin, eles rapidamente reconhecem boas partes
de suas linguagens familiares e, ao mesmo tempo, ficam intrigados com outros recursos
incríveis aos quais não foram expostos antes. As ideias familiares em Kotlin fazem com que
os programadores se sintam em casa à medida que aprendem e adotam a linguagem,
mas as ideias que são novas para eles os tornam mais produtivos em comparação com as
linguagens com as quais estão acostumados. Essa é parte da razão pela qual os
programadores são apaixonados pelo Kotlin.
Machine Translated by Google

O maior aumento no interesse pelo Kotlin veio logo após o anúncio do Google de
que o Kotlin é uma linguagem oficial para o desenvolvimento do Android.
[4] O endosso do Google é certamente significativo, mas há mais motivos para estar
entusiasmado com o Kotlin.

Kotlin é uma das poucas linguagens que podem ser usadas para desenvolvimento
do lado do servidor, móvel/Android e front-end. O código, escrito apropriadamente, pode ser
compilado em bytecode Java ou pode ser transpilado (compilado do código-fonte de uma
linguagem para o código-fonte de outra linguagem) para JavaScript. Kotlin/Native oferece
suporte a plataformas de destino, incluindo iOS, macOS, Linux, Windows e WebAssembly,
para compilar seu código-fonte em binários nativos. Isso torna o Kotlin uma das poucas
linguagens que você pode usar para desenvolvimento full-stack.

Ao viajar pelo Kotlin, você poderá reconhecer vários desses recursos e traçar suas raízes:

Embora sintaticamente diferente, Kotlin é semanticamente semelhante ao Java,


facilitando a adaptação dos programadores Java.

Sem herdar de uma classe, você pode adicionar seus próprios métodos de
conveniência específicos de domínio às classes. Esses métodos, chamados de
funções de extensão, podem ser usados como métodos que fazem parte da classe
original, com suporte total ao ambiente de desenvolvimento integrado (IDE). É como
os métodos de extensão no estilo C# no Kotlin, embora o Kotlin tenha recursos muito
mais ricos.

A delegação costuma ser uma ferramenta de design melhor do que a herança para reutilizar código.

Kotlin, inspirado em linguagens como Groovy e Ruby, é versátil nas maneiras como você
pode delegar chamadas de método de um objeto para outro, sem comprometer
a segurança de tipo.

Você pode usar a sintaxe concisa e elegante de correspondência de argumentos em


Kotlin, que é semelhante à sintaxe Erlang e Scala, em vez do
Machine Translated by Google

série mais detalhada de instruções if-else aninhadas.

Estender funções e métodos existentes é fácil em Kotlin (embora exija recompilação devido
à incompatibilidade binária), graças aos recursos de seus parâmetros padrão,
semelhantes a JavaScript, Scala, Ruby e Python.

Argumentos nomeados, como em Groovy, Scala e Ruby, tornam o código altamente


expressivo, mais fácil de ler e menos sujeito a erros.

Onde fizer sentido, você pode sobrecarregar operadores em suas próprias classes
ou em classes de terceiros, assim como em linguagens como C++ e Groovy.

A elegância, fluência e natureza concisa do Kotlin se unem para suportar a criação de DSLs
internas, semelhantes a linguagens como Groovy e Ruby, mas com suporte total para
verificação de tipo estático.

Você pode escrever procedimentos no estilo C, scripts no estilo Scala, código OO


semelhante ao Java e código no estilo funcional semelhante ao Smalltalk/Erlang em Kotlin.

Kotlin está liderando a inovação na área de programação assíncrona com corrotinas e


continuações.

Esses são apenas alguns dos recursos importantes que são proeminentes no Kotlin.
Machine Translated by Google

Razões para amar Kotlin

Depois de se aprofundar, Kotlin parece mais um canivete suíço do que um coquetel –


você pode fazer muito com essa linguagem com tão pouco código. A linguagem suporta
vários paradigmas. É digitado estaticamente com uma boa dose de forte inferência de
tipo. Ele pode ser compilado para bytecode Java, transpilado para JavaScript ou pode
ter como alvo binários nativos usando Kotlin/Native. É altamente fluente e elegante, e é
um charme para trabalhar. Vamos explorar mais detalhadamente os motivos para adotar
o Kotlin.

Programação Multiparadigma
Kotlin nos trata como adultos, oferece opções e nos permite escolher a abordagem mais
adequada para o problema em questão. A língua tem poucas cerimônias;
você não é obrigado a escrever tudo nas classes nem a compilar cada parte do código.
A linguagem é em grande parte sem opinião e oferece diferentes paradigmas
de programação para você escolher ou até mesmo misturar.

Você pode ver os diferentes paradigmas de programação suportados em Kotlin na


figura a seguir.

Você pode escrever código processual - isto é, código e funções diretamente em um


arquivo - como em JavaScript ou C, e pode executá-lo como um script, sem nenhuma
etapa extra de compilação, mas com a excepcional segurança de tipo que você espera de um
Machine Translated by Google

linguagem digitada estaticamente. A vantagem é que você pode fazer prototipagem


rápida de suas ideias ou ilustrar como um determinado padrão de design pode ser usado,
mas sem se afogar nas cerimônias que outras linguagens muitas vezes impõem.
Isso proporciona o menor tempo entre a ideia e a demonstração.

Assim como em Java, você pode criar classes e escrever código orientado a objetos em
Kotlin, mas sem muito código clichê. Portanto, é necessário menos código para
obter os mesmos resultados que em Java. Kotlin orienta você na criação de sua
hierarquia de classes intencionalmente, e não acidentalmente. As classes são finais por
padrão e se você pretende que uma classe sirva como classe base, você deve
especificar isso explicitamente. Além disso, a delegação possui uma sintaxe no nível da
linguagem, portanto podemos selecionar com prudência entre herança e delegação.

Embora o mundo mainstream tenha usado predominantemente o estilo imperativo de


programação, o código escrito usando o estilo funcional é menos complexo, mais
expressivo, conciso, elegante e fluente. Kotlin fornece suporte excepcional para o estilo
de programação imperativo e funcional. Você pode se beneficiar prontamente dos
principais recursos funcionais com os quais está acostumado em outras linguagens que
suportam o paradigma.

Você pode fazer uso imediato da elegância e da cerimônia baixa da sintaxe Kotlin para
criar linguagens internas específicas de domínio (DSLs). Além de criar suas próprias
APIs fluentes, você também pode se beneficiar da fluência em diversas bibliotecas
diferentes, por exemplo, a API Kotlin para a estrutura Spring.[5]

Além de programar simultaneidade usando o Java Development Kit (JDK), você também
pode escrever programas assíncronos usando as corrotinas do Kotlin. Esse
recurso é fundamental para aplicações que utilizam serviços em nuvem ou são
implantadas como microsserviços; permite interagir de forma eficiente com
outros serviços para trocar dados de forma assíncrona.

Digitado estaticamente com inferência de tipo


Machine Translated by Google

Linguagens de tipo estaticamente oferecem segurança de tipo em tempo de compilação,


mas Kotlin caminha alguns quilômetros extras para evitar erros comuns que são prováveis
em outras linguagens de tipo estaticamente. Por exemplo, o sistema de tipos Kotlin distingue
tipos anuláveis de tipos não anuláveis. Ele também possui inferência de tipo muito forte, na
mesma linha de linguagens como Scala, F# e Haskell. Você não precisa gastar seu
tempo digitando detalhes de tipo que são óbvios para todos que olham o código. Ao mesmo
tempo, quando o tipo pode não ser 100% claro, o Kotlin exige que você o especifique. Não
é excessivamente zeloso - ele suporta inferência de tipo na medida certa, para que
possamos ser produtivos e, ao mesmo tempo, o código possa ter tipo seguro.

Uma linguagem para desenvolvimento Full Stack


Assim como javac compila o código-fonte Java em bytecode para execução na Java
Virtual Machine (JVM), kotlinc-jvm compila o código Kotlin em bytecode para execução em
máquinas virtuais. Você pode escrever seu código do lado do servidor e aplicativos Android
usando Kotlin e direcionar a versão específica da máquina virtual que deseja usar
para implantação. Assim, seu código Spring no back-end e seu código nativo Android ou
iOS nos dispositivos podem ser escritos usando a mesma linguagem. Quando necessário,
você também pode misturar código Kotlin com código Java – nenhum código legado
precisa ser deixado para trás.

Kotlin também transpila para JavaScript. Você pode escrever código Kotlin que pode ser
transformado em JavaScript e executado em Node.js no lado do servidor ou em navegadores
no front-end da web.

Usando Kotlin/Native, você pode compilar código em binário nativo para execução
em plataformas específicas e em WebAssembly para execução em navegadores.

Fluente e elegante

Algumas linguagens impõem grande cerimônia e forçam você a criar código padrão. Alguns
desenvolvedores argumentam que os IDEs eliminam o fardo de ter que escrever esse
código manualmente. É verdade, mas mesmo que os IDEs vomitassem isso
Machine Translated by Google

código padrão, sua equipe precisa gastar tempo e esforço mantendo esse código
todos os dias. Linguagens como Scala, Groovy e Ruby sintetizam código que os
programadores terão que escrever. Da mesma forma, Kotlin cria algumas
coisas para você, como campos, getters e setters, seguindo implicitamente a
convenção JavaBean. Menos esforço, melhores resultados.

Kotlin torna algumas coisas opcionais. Por exemplo, um ponto e vírgula é opcional.
Não tendo que colocar o ; O símbolo leva a uma sintaxe mais fluente – essencial
para a criação de DSLs internas de fácil leitura. Kotlin também fornece uma anotação
infixa que podemos usar, tornando o ponto e os parênteses opcionais. Com
esses recursos você pode escrever código fluente e elegante como este:

operar o robô {vire à


esquerda
vire à direita
siga em frente
}

Sim, não é ficção - é código Kotlin real; você aprenderá a criar seu próprio código
fluente como este posteriormente neste livro, sem a necessidade de analisadores
ou ferramentas externas.
Machine Translated by Google

Por que você deve escolher Kotlin?


Kotlin pode ser a escolha certa para o seu projeto atual, ou para o próximo, por
muitas razões:

Kotlin cumpre a promessa “menos é mais”: você escreve menos código


padronizado. Quanto menos código você escreve, menos sua equipe precisa manter,
resultando em menos erros para lidar.

Kotlin oferece a liberdade de misturar os estilos de programação imperativos e


funcionais; você escolhe o que é melhor para o problema em questão.
Além disso, você pode escrevê-lo de uma maneira e refatorá-lo mais tarde, conforme desejar
– fazê-lo funcionar e, em seguida, melhorá-lo em breve.

Kotlin oferece muito mais segurança em tempo de compilação quando comparado a muitas
outras linguagens de tipo estaticamente. O código que você escreve falhará menos e
falhará rapidamente – durante a compilação, e não no tempo de execução. Esta é uma
das razões pelas quais a equipe do Spring[6] decidiu adotar o Kotlin.

As corrotinas Kotlin facilitam muito a criação de código assíncrono de alto desempenho,


em comparação com o que está disponível no Java Development Kit.

Alguns dos recursos programados para aparecer em versões futuras do Java já estão no
Kotlin. Você pode experimentar e se beneficiar do Java futuro agora mesmo usando
o Kotlin.

Você pode misturar código Kotlin e Java em seus projetos – usar Kotlin não é uma proposta
de tudo ou nada.

Você pode não apenas usar sintaxe fluente semelhante a DSL para interagir com APIs, como
na API Spring Kotlin, mas também projetar suas próprias APIs para serem fluentes e
expressivas para programadores que usam seu código.
Machine Translated by Google

Você pode reduzir a duplicação entre partes do seu sistema com Kotlin.
Por exemplo, as mesmas regras de negócios que verificam a entrada dos usuários
podem ser compiladas para bytecode Java para validações de back-end,
transpiladas para JavaScript para validação de front-end, compiladas para binários
nativos para execução em plataformas específicas como iOS e Android, ou para
WebAssembly para ser executado em navegadores.

Por fim, Kotlin é uma ótima opção para desenvolvimento Android, pois é a linguagem
oficial dessa plataforma.

Você verá mais sobre por que Kotlin é interessante nas muitas páginas deste livro. Apertem
os cintos – vai ser um passeio divertido. Vamos começar instalando o SDK para que possamos
começar a escrever Kotlin.
Machine Translated by Google

Levando Kotlin para um passeio


O restante do livro focará na sintaxe e na semântica da linguagem Kotlin. Para
aprender completamente os conceitos, você vai querer praticar os exemplos. Esta seção
mostrará como configurar e verificar o ambiente necessário em seu sistema.

Depois de digitar seu código, o Kotlin oferece uma variedade de opções para executar
o código. Ao contrário do Java, você não precisa compilar cada linha de código. Você pode
executar o código como está, diretamente do código-fonte em um arquivo, se desejar.
Como alternativa, você pode criar arquivos de classe e reutilizar o binário para
executar outras classes ou arquivos Kotlin. Enquanto estiver escrevendo o código, você
pode iniciar o shell Kotlin para experimentar o comportamento de um pequeno trecho de
código. Você pode executar seu código na JVM, em um mecanismo JavaScript no
Node.js ou no navegador, ou em dispositivos Android, e também pode executá-lo
em destinos nativos como iOS e WebAssembly.

São muitas opções, mas antes de podermos exercer qualquer uma delas, precisamos do
SDK, então vamos instalá-lo primeiro.

Instale o SDK Kotlin


Se você estiver usando uma versão recente do IntelliJ IDEA,[7] o Kotlin vem junto
com o IDE. Se você planeja compilar e executar código apenas dentro desse IDE, está tudo
pronto.

Mas mesmo que todos nós usemos IDEs, é bom começar aprendendo como
compilar e executar na linha de comando, pois isso lhe dá total exposição à
construção do código. Instale o compilador independente no link Baixar compilador
do site Kotlin. Isso o levará à página Trabalhando com o Compilador de Linha de
Comando.[8] Você pode baixar e descompactar os arquivos zip para instalar, usando
Homebrew ou uma das outras opções,
Machine Translated by Google

dependendo do seu sistema operacional. Você também precisará do JDK 1.6[9] ou posterior
em seu sistema.

Se você quiser compilar o código usando ferramentas de construção como Maven ou


Gradle, consulte as instruções no site Kotlin.[10] Mais adiante no livro, quando estivermos
prontos para escrever testes e misturar Kotlin com Java, usaremos arquivos de projeto
Maven e Gradle.

Verifique a instalação
Depois de instalar e definir o caminho para onde o Kotlin está instalado, verifique se tudo
está definido executando o seguinte comando:

$ kotlinc-jvm -versão

A saída desse comando, se o Kotlin tiver sido instalado corretamente, mostrará o número
da versão, assim:

informações: kotlinc-jvm 1.3.41 (JRE 12.0.2+10)

Não se preocupe com a versão específica do JRE na saída. A saída que você verá no seu
sistema refletirá a versão do Java que você já instalou.

Depois de verificar a instalação, passe para a próxima etapa para escrever um pequeno
trecho de código Kotlin e executá-lo.
Machine Translated by Google

Compilar para Bytecode e Executar

Vamos primeiro criar um pequeno programa Hello World em Kotlin. Usando seu editor de texto
favorito, crie um arquivo chamado Hello.kt, assim:

correndo/Hello.kt

fun main() = println( "Olá Mundo")

Não se preocupe com a sintaxe do código neste momento; vamos manter nosso foco em fazer o
código rodar. Discutiremos a sintaxe e a semântica da linguagem nos capítulos seguintes. Você
pode especificar o parâmetro para a função main() se desejar, mas a partir do Kotlin 1.3, isso é
opcional. Se você estiver usando uma versão anterior à 1.3, você precisará adicionar o
parâmetro, assim: fun main(args:

Matriz<String>).

Executando na linha de comando


Para compilar e executar o código na linha de comando, primeiro execute o seguinte
comando:

$ kotlinc-jvm Olá.kt -d Olá.jar

Este comando irá compilar o código do arquivo Hello.kt no bytecode Java e colocá-lo no
arquivo Hello.jar .

Depois que o arquivo jar for criado, execute o programa usando a ferramenta java , assim:

$ java -classpath Olá.jar HelloKt

Como o arquivo Hello.kt contém apenas a função principal e não uma classe, o compilador
Kotlin, kotlinc-jvm, cria automaticamente uma classe com o nome do arquivo, sem a extensão .kt ,
mas adiciona um sufixo Kt .

Aqui está o resultado da execução do código:


Machine Translated by Google

Olá Mundo

Em vez de especificar a opção de linha de comando classpath , você também pode usar
a opção jar para executar o código. Isso porque, ao encontrar a função main() , o
compilador Kotlin decidiu adicionar o atributo de manifesto Main-Class ao arquivo jar. Vá
em frente e experimente o seguinte comando no arquivo Hello.jar :

$ java -jar Olá.jar

A saída deste comando será a mesma produzida quando a opção classpath foi usada
em vez da opção jar .

Neste exemplo não usamos nada da biblioteca padrão Kotlin.


No entanto, qualquer programa não trivial fará uso de classes e funções da biblioteca
padrão Kotlin e, nesse caso, a execução acima usando a ferramenta java falhará com uma
exceção java.lang.NoClassDefFoundError . Para evitar isso, inclua o arquivo kotlin-
stdlib.jar no caminho de classe, assim:

$ kotlinc-jvm Olá.kt -d Olá.jar $ java


-classpath Olá.jar:$KOTLIN_PATH/lib/kotlin-stdlib.jar OláKt

A variável de ambiente $KOTLIN_PATH em sistemas do tipo Unix, ou


%KOTLIN_PATH% no Windows, refere-se ao diretório onde o Kotlin está
instalado. No Windows, em vez de :, use ; separar os caminhos no
caminho de classe.

Em vez de usar a ferramenta java , você também pode usar a ferramenta kotlin . Nesse caso, você

não precisa consultar kotlin-stdlib.jar. Vamos executar o código usando kotlin.

Aqui estão os passos, mas você pode pular o primeiro passo; é o mesmo comando de
compilação de antes:

$ kotlinc-jvm Olá.kt -d Olá.jar $ kotlin


-classpath Olá.jar OláKt
Machine Translated by Google

A saída do código será a mesma, quer executemos o código usando a ferramenta java ou a
ferramenta kotlin .

Use a ferramenta java se você estiver programando predominantemente em Java e


misturando Kotlin em seu projeto. Caso contrário, use a ferramenta kotlin , pois ela
precisa de menos opções de configuração.

Executando em IDEs
Não deve ser surpresa que o IntelliJ IDEA da JetBrains, que também é a empresa por trás do
Kotlin, tenha excelente suporte para programação com a linguagem. Alguns
desenvolvedores acham que precisam desse IDE para usar Kotlin, mas isso não é verdade.
Kotlin não exige que você use um IDE específico ou qualquer IDE.

Kotlin vem com as versões mais recentes do IntelliJ IDEA e também com o

Edição da comunidade IntelliJ IDEA gratuita e de código aberto. Para usar o IntelliJ
IDEA para desenvolvimento com Kotlin, comece criando um projeto Kotlin. Depois de criar um
projeto, você pode criar rapidamente arquivos Kotlin e executá-los com apenas alguns cliques
do mouse ou atalhos de teclado. O breve tutorial[11] no site oficial do idioma lhe dará um
início rápido se você ficar preso em alguma etapa.

Se você é um aficionado pelo Eclipse, pode usar o Eclipse Neon ou posterior para programar
com Kotlin. O site oficial da linguagem Kotlin também tem um tutorial para Eclipse,[12] para
ajudá-lo a começar a usar Kotlin no Eclipse.

Os fãs do NetBeans podem se beneficiar de um plug-in NetBeans Kotlin[13] para


programar aplicativos Kotlin.

Verifique se você está usando a versão correta do IDE e a versão correta do Kotlin
compatível com essa versão.

Experimente o REPL
Machine Translated by Google

Várias linguagens fornecem um shell de linha de comando read-evaluate-print loop (REPL) para
executar pequenos trechos de código. Gosto de chamá-los de ferramentas de
microprototipagem. Quando você está no meio da codificação ou da aprovação do
seu teste automatizado atual, em vez de se perguntar o que uma função específica faz, você
pode rapidamente dar um passeio no REPL. Depois de verificar se um pequeno trecho de
código é o que você está procurando, você pode usar a melhor ferramenta que os humanos
inventaram – copiar e colar – para trazê-lo do REPL para o seu editor ou IDE. A ferramenta
interativa também é muito útil para mostrar a um colega como funciona um pequeno trecho
de código, sem a necessidade de criar um projeto em um IDE, por exemplo.

O compilador Kotlin que usamos anteriormente, kotlinc-jvm, se transforma em um shell REPL


quando executado sem quaisquer opções ou nomes de arquivo. Vamos realizar uma sessão
interativa. Na linha de comando, digite o comando kotlinc-jvm e o REPL responderá
com um prompt para você digitar algum código. Digite algum código, como na sessão
interativa a seguir, e observe o
resposta:

$ kotlinc-jvm
Bem-vindo ao Kotlin ...
Digite :help para obter ajuda, :quit para sair
>>> 7 + 5
res0: kotlin.Int = 12 >>> val
list = listOf(1, 2, 3) >>> list.map { it * 2 }
res2:
kotlin.collections.List<kotlin.Int> = [2, 4, 6]
>>>
$

Assim que você digitar um trecho de código e pressionar a tecla Enter , o REPL avaliará esse
trecho de código, exibirá a resposta e solicitará o próximo trecho. Quando terminar,
pressione ctrl+d (ctrl+c no Windows) ou digite :quit para encerrar a sessão REPL.

De dentro do REPL, você também pode carregar arquivos existentes para executar código
neles. Por exemplo, vamos carregar o arquivo Hello.kt que criamos anteriormente e executá-lo
Machine Translated by Google

dentro do REPL, sem passar por uma etapa de compilação explícita.

$ kotlinc-jvm
Bem-vindo ao Kotlin ...
Digite :help para obter ajuda, :quit para sair
>>> :load Hello.kt >>>
main()
Olá Mundo
>>>
$

Você também pode especificar o caminho de classe para seus próprios arquivos jar ou
arquivos jar de terceiros ao iniciar o REPL. Em seguida, você também pode usar instâncias de
suas classes ou classes de terceiros do REPL de forma interativa.

Executar como script

Você viu anteriormente como compilar o código Kotlin em bytecode, criar um arquivo jar e, em
seguida, executar o código usando os comandos java ou kotlin . Esse processo de duas etapas
é útil quando você tem vários arquivos em um aplicativo grande.
Mas nem tudo o que escrevemos é de grande porte ou em escala empresarial – scripts de
shell e arquivos em lote têm seu lugar.

Para executar algumas tarefas de back-end, analisar alguns arquivos, copiar arquivos com base em
alguma configuração – em outras palavras, para coisas que você normalmente usaria scripts de shell
– você pode escrever um script usando Kotlin. A vantagem de fazer isso é que você não precisa se
lembrar dos comandos shell entre sh, zsh, bash, Windows CMD, PowerShell e assim por

diante. E você pode usar uma linguagem poderosa e fluente para realizar as tarefas. Depois de
implementar a tarefa desejada em Kotlin, você pode executá-la como script, em uma única etapa,
em vez de compilar explicitamente o código para criar bytecode.

Se o código tiver um erro de sintaxe, a execução do script falhará sem realmente executar
qualquer parte do script; portanto, é tão seguro executar um script quanto compilar e executar.
Machine Translated by Google

Vamos escrever um script Kotlin para listar todos os arquivos com extensão kts no diretório
atual. Aqui está o código para isso:

executando/listktsfiles.kts

java.io.File( ".") .walk() .filter { arquivo ->


arquivo.extension == "kts" } .forEach { println(it) }

O conteúdo do arquivo não é diferente de um arquivo Kotlin normal que você escreveria. A
única diferença está no nome do arquivo, a extensão kts – para indicar a intenção de executar
como um script – em vez da extensão kt .

O código usa a classe File do pacote JDK java.io e também usa as funções de extensão que
Kotlin adicionou a essa classe. Ele percorre todos os arquivos no diretório atual (.) , filtra ou
seleciona apenas os arquivos que terminam com a extensão kts e imprime o objeto de arquivo
– ou seja, o caminho completo e o nome de cada arquivo selecionado.

Para executar este arquivo, usaremos o comando kotlinc-jvm , mas desta vez, em vez de

compilar, pediremos à ferramenta para executar o código como script imediatamente. Para isso,
use a opção -script , assim:

$ kotlinc-jvm -script listktsfiles.kts

Aqui está a saída deste código:

./listktsfiles.kts

Em sistemas do tipo Unix, se você deseja executar o script sem prefixar com kotlinc-jvm
-script, então você pode usar o recurso shebang, assim:

correndo/greet.kts

#!/usr/bin/env kotlinc-jvm -script

println( "oi")
Machine Translated by Google

Certifique-se de executar chmod +x greet.kts para dar permissão de execução ao arquivo.

Em seguida, execute o arquivo diretamente da linha de comando, assim:

$ ./greet.kts

Isso produzirá a saída:

oi

Em alguns sistemas, você deve fornecer o caminho completo para o local do kotlinc-jvm
em vez de /usr/bin/env para que o recurso shebang funcione corretamente.

Se você pretende usar scripts em produção, o kscript[14] pode ser útil. É uma biblioteca
que oferece vários recursos para trabalhar com scripts Kotlin, incluindo cache de
script compilado.

O código Kotlin não só pode ser compilado para bytecode Java, mas também para
vários outros formatos, como veremos a seguir.
Machine Translated by Google

Compilando para outros destinos


Além de todos os recursos que o Kotlin oferece, é uma das poucas linguagens
que pode ser compilada para diferentes alvos.

Em dispositivos Android: Kotlin é considerada uma linguagem de primeira


classe para desenvolvimento Android. Exploraremos o uso do Kotlin para criar
aplicativos Android no Capítulo 20, Escrevendo aplicativos Android com Kotlin.

Para JavaScript: a transpilação é a compilação do código-fonte de uma linguagem


para o código-fonte de outra linguagem. Você pode ver como transpilar Kotlin para
JavaScript no Apêndice 1, Transpilando para JavaScript
.

Para destinos nativos: quando compilar para uma máquina virtual não é uma
opção, Kotlin/Native pode ser usado para compilar seu código-fonte para
diferentes destinos nativos, como iOS, Linux, MacOS, Windows e outros, e pode
ser executado sem um máquina virtual. Consulte o Apêndice 2, Kotlin/
Native, para obter uma introdução ao uso do Kotlin/Native.

Para que o WebAssembly seja executado em navegadores: usando Kotlin/


Native, você também pode compilar o código-fonte Kotlin para WebAssembly ou
Wasm,[15] que é um formato binário para máquinas virtuais executadas
em navegadores modernos. No Apêndice 3, Kotlin para WebAssembly,
exploraremos esse recurso para criar código Kotlin que é executado em navegadores.
Machine Translated by Google

Qual opção escolher?


Kotlin não determina qual opção você escolhe para executar o código; depende inteiramente de
você, dependendo de suas necessidades e gostos. Aqui estão algumas coisas a considerar
ao escolher sua opção:

Para misturar código Kotlin com Java ou outras linguagens na JVM, compile o
código usando kotlinc-jvm. Em seguida, simplesmente jogue o arquivo jar no classpath
ou modulepath junto com uma referência ao arquivo kotlin-stdlib.jar e use-o como usaria
qualquer jar criado a partir do código-fonte Java usando javac.

Se você tiver vários arquivos Kotlin e pretende executar o programa como um


programa Kotlin, use a ferramenta Kotlin para executar o código.

Para implementar tarefas de nível de sistema ou de back-end usando Kotlin, crie um


único arquivo Kotlin e execute-o como script usando a opção -script .
Como alternativa, use o shebang para executar o arquivo diretamente na linha
de comando ou em uma tarefa cron.

Para aproveitar a digitação estática e a verificação em tempo de compilação que vem


com o Kotlin para a criação de aplicativos da web, use a opção de compilar Kotlin para
JavaScript.

Para executar o código Kotlin em diferentes plataformas nativas, como iOS e


WebAssembly, use Kotlin/Native para compilar o código para os destinos desejados.

Durante o desenvolvimento ativo, execute o código de dentro do IDE para facilitar o


desenvolvimento e a conveniência oferecida pelos IDEs.

Para experimentar pequenos trechos de código, execute kotlinc-jvm como REPL.


Machine Translated by Google

Empacotando
Kotlin é uma linguagem de escolhas, e esse espírito brilha desde o início com suporte para
múltiplos paradigmas de programação e uma série de opções para executar código Kotlin. Kotlin
não determina como você deve escrever aplicativos. Você pode começar aos poucos, com
apenas algumas linhas para construir scripts, e pode pedir à linguagem que o leve até a
construção de aplicativos altamente complexos com classes e dependências. Você pode usar
Kotlin para criar aplicativos do lado do servidor, opcionalmente com Spring. Você pode criar
aplicativos Android, transpilar Kotlin para JavaScript e também usar Kotlin/Native para
compilar para plataformas nativas direcionadas, como iOS e WebAssembly. A natureza versátil
do Kotlin o torna uma das poucas linguagens de programação full-stack.

Você pode compilar em bytecode Java e executar na JVM. Alternativamente, você pode executá-
lo como um script, ignorando a etapa extra de compilação. Se você gosta de desenvolvimento
front-end, poderá obter segurança em tempo de compilação junto com todos os benefícios do
Kotlin para transpilar o código para JavaScript. E para explorar pequenos trechos de código, você
pode usar o Kotlin REPL.

Neste capítulo, você obteve alguns insights de alto nível sobre os recursos do Kotlin e começou
a usá-lo. A seguir, você aprenderá os fundamentos da linguagem que usará todos os dias ao
programar com Kotlin.

Notas de rodapé

[2] https://twitter.com/abreslav

[3] https://www.jetbrains.com/

[4] https://developer.android.com/kotlin

[5] https://spring.io/blog/2017/08/01/spring-framework-5-kotlin-apis-the-funcional-way

[6] https://spring.io/blog/2017/01/04/introduzindo-kotlin-support-in-spring-framework-5-0

[7] https://www.jetbrains.com/idea/download
Machine Translated by Google

[8] https://kotlinlang.org/docs/tutorials/command-line.html

[9] http://openjdk.java.net/

[10] https://kotlinlang.org/

[11] https://kotlinlang.org/docs/tutorials/getting-started.html

[12] https://kotlinlang.org/docs/tutorials/getting-started-eclipse.html

[13] http://plugins.netbeans.org/plugin/68590/kotlin

[14] https://github.com/holgerbrandl/kscript

[15] https://webassembly.org/

Copyright © 2020, The Pragmatic Bookshelf.


Machine Translated by Google

Parte 1
Scripts com Kotlin
Kotlin é uma linguagem escalável – você pode criar scripts com
poucas linhas ou um aplicativo corporativo inteiro com
muitas classes e bibliotecas. Nosso objetivo é agregar valor,
não escrever muito código. Desse ponto de vista, a
concisão e a eficácia de cada linha de código são importantes.

Nesta parte, você aprenderá sobre inferência de tipos,


definição de variáveis, uso de modelos de string e criação
de strings multilinhas. Em seguida, veremos como criar
funções para iterar com elegância em intervalos de valores e
processar dados usando os recursos de correspondência de argumentos do Kotlin.

Você aprenderá a criar scripts, mas esse conhecimento o


levará adiante na criação de código OO, na escrita de
código funcional... até a criação de aplicativos
corporativos e Android.
Machine Translated by Google

Capítulo 2

Fundamentos de Kotlin para os olhos de Java

Coisas simples devem ser fáceis de criar e coisas complicadas devem ser acessíveis. Rápido,
quantas linhas de código você precisa para encontrar programaticamente
o número de núcleos em uma máquina? Que tal o seguinte:

println(Runtime.getRuntime().availableProcessors())

Esse é o programa inteiro em Kotlin – com apenas meia linha de código, sem necessidade de
ponto e vírgula, sem importações e usando o Java JDK, mas com muito menos código e
cerimônia. Esse é Kotlin.

Kotlin trata de realizar seu trabalho; não impõe cerimônia a você.


Você pode começar pequeno e aumentar. A programação é uma série de
miniexperimentos; você frequentemente cria protótipos de soluções para ver se as coisas fazem
sentido e escreve código para ter uma ideia e desenvolver ideias de design. Os scripts Kotlin
são uma ótima maneira de conseguir isso rapidamente, sem escrever código desnecessário.

Neste capítulo, você aprenderá alguns princípios básicos — os blocos de construção que
normalmente fazem parte do corpo de funções e métodos, mas que também podem ser inseridos
diretamente em scripts em Kotlin. Isso inclui definir variáveis de números e strings, criar
constantes, especificar as informações de tipo, criar uma expressão de string com valores
incorporados, criar strings multilinhas – uma miscelânea de recursos que usaremos
frequentemente ao programar.
Machine Translated by Google

com Kotlin, seja escrevendo scripts, criando classes ou escrevendo código de


estilo funcional.

Programadores Java experientes que começam a programar em Kotlin precisam


desaprender algumas de suas práticas Java enquanto aprendem as nuances do Kotlin.
Neste capítulo, veremos coisas que os olhos muito familiarizados com Java precisam se
ajustar ao fazer a transição para Kotlin. Assim como usar um novo par de óculos
ou lentes de contato, leva algum tempo para se acostumar, mas a elegância de Kotlin
fará com que você se sinta confortável rapidamente.

Começaremos apreciando a concisão em Kotlin. Cada linha de código é importante


– você não pode tornar um aplicativo inteiro conciso quando as operações mais
fundamentais são detalhadas. Quer você escreva código no estilo imperativo, no estilo
funcional ou orientado a objetos, as expressões e instruções são os blocos de construção.
Kotlin remove cerimônia, ruído e desordem de cada linha de código, para que seu
programa geral possa ser mais curto, mais expressivo e mais fácil de manter.

Kotlin torna opcionais uma série de coisas que são exigidas em outras
linguagens – ponto e vírgula, especificações explícitas de tipo e classes, para mencionar
algumas. Kotlin exige que você tome uma decisão consciente no momento de criar
uma variável se ela deve ser mutável ou imutável. Ele fornece modelos de string para
facilitar a criação de expressões de string e strings multilinhas. E favorece
expressões em vez de declarações, para reduzir a necessidade de variáveis mutantes.

Vamos mergulhar e ver a raiz da filosofia de design do Kotlin na parte mais


rudimentar do código, uma única linha de declaração ou expressão. Ao longo do caminho,
veremos como o Kotlin reduz o ruído no código e como você pode definir variáveis,
usar inferência de tipo, confiar em avisos sensatos, incorporar facilmente
expressões em strings e criar strings multilinhas. Aprender primeiro esses conceitos
fundamentais e essenciais ajudará a influenciar cada linha de código que você escreve
em Kotlin.
Machine Translated by Google

Menos digitação

Você digitará menos – aquele ato de martelar as teclas do teclado – para criar
aplicativos com Kotlin. Isso ocorre porque muitas coisas que consideramos obrigatórias são
opcionais no Kotlin.

Ponto e vírgula é opcional

Quando você começa a programar em Kotlin, seu dedo mínimo direito obtém alívio
imediato das lesões por esforço repetitivo que pode ter sofrido durante a maior parte de sua
carreira de programação. Embora você possa, não é necessário terminar cada instrução
ou expressão com ponto e vírgula. Use o ponto-e-vírgula com moderação – apenas nas
ocasiões em que desejar colocar duas ou mais expressões ou instruções em uma
única linha.

O exemplo a seguir é uma sintaxe válida em Kotlin e pode ser escrito de forma
independente:

6*2

À primeira vista, pode não parecer grande coisa, mas, como você verá mais adiante neste
livro, não ter que colocar ponto-e-vírgula torna o código fluente, especialmente ao criar
DSLs internas.

Se você estiver migrando de linguagens como Java e JavaScript para Kotlin, é provável
que pressionar a tecla de ponto-e-vírgula seja uma ação involuntária agora.
Isso é compreensível, mas crie o hábito de omitir ponto-e-vírgula ao escrever em Kotlin.

A especificação do tipo de variável é opcional

Kotlin é digitado estaticamente, mas isso não significa que você precise especificar
os detalhes dos tipos de variáveis. A tipagem estática significa que o tipo de variáveis é
verificado e a sanidade do tipo é garantida em tempo de compilação.
Machine Translated by Google

Kotlin tem inteligência - inferência de tipo - para determinar o tipo de variáveis com base no
contexto. Vamos definir uma variável sem especificar o tipo e depois perguntar o tipo dessa variável.

essência/typeinference.kts

val saudação = "olá"

println(saudação)
println(saudação::
classe) println(saudação.javaClass)

A chamada ::class está solicitando a classe Kotlin do objeto referenciado pela variável. A

chamada .javaClass , entretanto, está solicitando a classe Java subjacente.

É raro que as classes Kotlin e Java sejam diferentes – apenas as classes que são intimamente
conhecidas pelo compilador Kotlin exibirão tais diferenças.

No exemplo anterior, o recurso de inferência de tipo do Kotlin determina que o tipo de saudação é
String com base no valor atribuído a ele. A saída mostra estes detalhes:

olá
classe kotlin.String
classe java.lang.String

Alguns desenvolvedores temem a inferência de tipo; eles se perguntam se isso é uma questão de
tempo de execução e se de alguma forma diminui a eficácia da verificação de tipo em tempo de
compilação. A resposta curta é não.

Para ser justo, o código acima revelou o tipo do objeto referenciado em tempo de execução,
mas qual é o tipo da variável greet em tempo de compilação? Podemos descobrir isso cometendo

um erro no código, assim:

essência/typechecking.kts

val saudação = "olá"

println(saudação)
Machine Translated by Google

cumprimentar = 0

Kotlin determinou que o tipo de greet é String em tempo de compilação e, como


resultado, sabia que atribuir um número inteiro a ele não é válido. Além
disso, a reatribuição de um val não é permitida. Portanto o código não foi executado e
resultou em erros de compilação, mesmo tendo sido executado como script.
Os erros de compilação resultantes são:

typechecking.kts:5:1: erro: val não pode ser reatribuído greet = 0

typechecking.kts:5:9: erro: o literal inteiro não está em conformidade com o tipo


esperado String greet = 0

Kotlin não leva a inferência de tipo ao extremo – ele permite omitir os detalhes do tipo
apenas em locais onde o tipo é óbvio. Ao definir funções e métodos, você deve
especificar o tipo dos parâmetros, embora possa omitir o tipo de retorno. Em
geral, especifique o tipo de retorno para APIs que não são internas às suas bibliotecas,
mas que são visíveis para o usuário externo. Discutiremos isso mais detalhadamente
quando explorarmos a criação de funções.

De sua parte, incentive seus colegas a dar nomes significativos às variáveis, para
que seja mais fácil identificar o tipo e a intenção das variáveis.
Por exemplo, val taxRate = 0,08 é melhor que val t = 0,08.

Além disso, ao usar a inferência de tipos, resista à tentação de incorporar as


informações de tipo em nomes de variáveis — tais esforços são o desejo dos
programadores de compensar excessivamente por não especificarem o tipo que
estão tão acostumados a fornecer. Por exemplo, evite o seguinte:

val taxRateDouble = 0.08 //Não faça isso // ou val

dTaxRate = 0.08 //Além disso, não faça isso


Machine Translated by Google

Variáveis locais são internas e não são vistas pelos usuários do seu código. Portanto, o
uso da inferência de tipos não retira nenhum detalhe dos usuários de suas funções.
Deixe de fora os detalhes do tipo sempre que possível e, em vez disso, use a
inferência de tipo com nomes descritivos, mas não necessariamente longos, para variáveis.

Classes e funções são opcionais


Ao contrário de linguagens como Java, Kotlin não exige que uma instrução ou expressão
pertença a um método e que um método pertença a uma classe, pelo menos não no
código-fonte que escrevemos. Quando o código é compilado ou executado como
script, o Kotlin criará classes e métodos wrapper conforme necessário para satisfazer
as expectativas da JVM.

No código-fonte a seguir, a função não pertence a uma classe e o código abaixo da


função é independente e não faz parte de nenhuma função.
No entanto, Kotlin se encarrega de agrupá-los, quando necessário, em classes para
satisfazer a JVM.

Vamos criar um script com uma função que não pertence a nenhuma classe e
algum código independente que não faz parte de nenhuma função.

essência/standalone.kts

divertido, nofluff() {
println( "nofluff chamado...")

throw RuntimeException( "ops")


}

println( "não está em uma função, chamando nofluff()")

tente
{ nofluff() }
catch(ex: Exceção) {
val stackTrace = ex.getStackTrace()
println(stackTrace[0])
println(stackTrace[1])
}
Machine Translated by Google

O corpo autônomo do código abaixo da função chama a função nofluff(), que não pertence
a nenhuma classe. A função explode com uma exceção e o código de chamada imprime os
dois primeiros quadros da pilha da exceção. A saída deste código mostra que,
primeiro, Kotlin não nos força a escrever classes e métodos e, segundo, ele agrupa o
código em uma classe automaticamente.

não em uma função, chamando nofluff() nofluff


chamado...
Autônomo.nofluff(autônomo.kts:4)
Autônomo.<init>(standalone.kts:10)

Kotlin silenciosamente transformou a função nofluff() em um método de uma classe


sintetizada chamada Standalone – um nome inferido do nome do arquivo – e o

código independente no construtor da classe, conforme indicado por <init> na saída.

Ao escrever pequenos trechos de código, coloque-o diretamente em um arquivo e execute-


o como um script – sem necessidade de cerimônia para criar classes e métodos. Mas ao
trabalhar em aplicações maiores, você pode criar classes e métodos.
Código simples pode ser simples, e código mais complexo pode ter melhor rigor e
estrutura.

try-catch é opcional
O compilador Java nos força a capturar ou propagar explicitamente exceções verificadas.
O debate sobre se as exceções verificadas são boas ou ruins pode nunca ser resolvido –
alguns desenvolvedores adoram, enquanto outros odeiam. Não precisamos ser arrastados
para essa briga; em vez disso, vamos nos concentrar no que o Kotlin oferece.

Kotlin não força você a capturar nenhuma exceção – marcada ou desmarcada. Se você não
colocar um try-catch em torno de uma chamada de função e se essa função falhar, a
exceção será automaticamente propagada para o chamador da sua função
Machine Translated by Google

ou código. Se uma exceção não for tratada, isso resultará no encerramento fatídico do
seu programa.

Em Java, por exemplo, o método sleep() da classe Thread lança uma exceção verificada e
o compilador nos força a lidar com ela. Como resultado, qualquer chamada para sleep()
deve ser cercada por um try e seguida por uma noite sem dormir, perguntando-se o
que fazer com aquela InterruptedException fedorenta que pode potencialmente
ser lançada a partir dessa chamada. Não há necessidade de perder o sono por causa
desses problemas em Kotlin:

essência/nocatch.kts

println( "Deixe-me tirar uma soneca")


Thread.sleep(1000)
println( "ah, isso é bom")

O código não possui nenhum try e catch, mas quando executado ele imprimirá as duas
linhas de saída com um atraso de um segundo após a impressão da primeira linha.

É uma boa prática programar defensivamente para lidar com exceções. Ao mesmo
tempo, como o Kotlin não nos força um try-catch , não ficamos tentados a colocar aqueles
blocos catch vazios que muitos programadores Java parecem escrever simplesmente para
silenciar o compilador Java. Lembre-se de que o que você não trata é propagado
automaticamente para o chamador.

Você viu como o compilador Kotlin oferece muita flexibilidade ao colocar menos
demandas. Ao mesmo tempo, o compilador procura possíveis erros no código, para
torná-lo mais seguro, como veremos a seguir.
Machine Translated by Google

Avisos sensatos
Mesmo que um trecho de código seja sintaticamente válido, alguns problemas potenciais
podem estar ocultos. Obter um aviso antecipado, durante o tempo de compilação, pode nos
ajudar a corrigir proativamente esses possíveis problemas. O compilador Kotlin procura
alguns problemas potenciais no código.

Por exemplo, se um parâmetro recebido em uma função ou método não for usado, o
compilador emitirá um aviso. No script a seguir, o parâmetro passado para
computate() não é usado.

essência/não utilizado.kts

computação divertida (n: Int) = 0

println(computação(4))

Ao executar este script, além de exibir o resultado, o Kotlin também reportará quaisquer
avisos para parâmetros não utilizados:

0
unused.kts:1:13: aviso: o parâmetro 'n' nunca é usado fun compute(n:
Int) = 0
^

É uma boa prática de desenvolvimento de software tratar avisos como erros — uma
prática ágil enfatizada em Práticas de um desenvolvedor ágil [SH06]. Kotlin facilita isso
com a opção -Werror . Para usar esta opção, coloque-a na linha de comando ao
compilar o código ou execute-o como um script, assim:

$ kotlinc-jvm -Werror -script não utilizado.kts

Esta opção falhará na construção ou execução. Ao contrário da execução anterior sem


essa opção, não haverá saída quando o script for executado; em vez disso, um erro é
relatado:

erro: avisos encontrados e -Werror especificado


Machine Translated by Google

unused.kts:1:13: aviso: o parâmetro 'n' nunca é usado fun compute(n:


Int) = 0
^

O compilador Kotlin é sensato ao dar avisos. Por exemplo, não é incomum que os
programas ignorem os argumentos da linha de comando. Forçar-nos a usar parâmetros
dados a main() é considerado draconiano, então Kotlin não reclama de parâmetros
não utilizados para main(), como veremos no próximo exemplo.
Mas se você tiver um parâmetro não utilizado em main() dentro de um script (um
arquivo .kts em vez de um arquivo .kt ), o Kotlin lhe dará um aviso – ele decide com
base no contexto.

essência/UnusedInMain.kt

computação divertida (n: Int) = 0

fun main(args: Array<String>) = println(compute(4))

Ao compilar o código usando kotlinc-jvm e executá-lo usando java ou kotlin, você obterá
a seguinte saída. O aviso é do kotlinc e a saída é da execução do arquivo jar gerado:

UnusedInMain.kt:1:13: aviso: o parâmetro 'n' nunca é usado fun compute(n:


Int) = 0
^

A partir do Kotlin 1.3, você pode omitir os parâmetros de main() se não precisar deles.

Vimos como Kotlin tenta fazer um ataque preventivo contra possíveis erros. Nesse
sentido, a linguagem quer que você seja decisivo quanto à imutabilidade. Vamos
explorar essa escolha a seguir.
Machine Translated by Google

Prefira val a var


Para definir uma variável imutável – isto é, uma constante ou um valor – use val, como
então:

val pi: Duplo = 3,14

Ao contrário do Java, onde você coloca o tipo antes do nome da variável, no Kotlin você
coloca o nome da variável primeiro, depois dois pontos, seguido pelo tipo. Kotlin considera
a sequência que Java exige como “colocar a carroça na frente dos bois” e dá mais ênfase
aos nomes de variáveis do que aos tipos de variáveis.

Como o tipo da variável é óbvio neste contexto, podemos omitir a especificação do


tipo e pedir ao Kotlin para usar a inferência de tipo:

valor pi = 3,14

De qualquer forma, o valor de pi não pode ser modificado; val é como final em Java.
Qualquer tentativa de alterar ou reatribuir um valor a variáveis definidas usando val
resultará em um erro de compilação. Por exemplo, o código a seguir não é válido:

valor pi = 3,14

pi = 3.14 //ERRO: val não pode ser reatribuído

E se quisermos alterar o valor de uma variável? Para isso, Kotlin tem var – também
conhecido como “palavra-chave da vergonha”. Variáveis definidas usando var podem
sofrer mutação à vontade.

Aqui está um script que cria uma variável mutável e depois modifica seu valor:

pontuação variável = 10

// ou pontuação var: Int = 10

println(pontuação) //10
Machine Translated by Google

pontuação = 11

println(pontuação) //11

Variáveis mutantes são um modo de vida no estilo imperativo de programação. Mas isso
é um tabu na programação funcional. Em geral, é melhor preferir a imutabilidade –
ou seja, val em vez de var. Aqui está um exemplo para ilustrar por que isso acontece
melhorar:

essência/mutate.kts

fator variável = 2

divertido doubleIt (n: Int) = n * fator

fator = 0

println(doubleIt(2))

Não execute o código; em vez disso, observe-o, mostre-o a alguns de seus colegas e
pergunte qual será o resultado do código. Faça uma enquete. O resultado será igual ao
que a maioria das pessoas disse que seria – brincadeira. A correção do programa não é
um processo democrático; felizmente, eu acho.

Você provavelmente obteve três respostas à sua enquete:

A saída é 4.
A saída é 0, eu acho.
O QUE – a resposta que o código evocou em alguém recentemente.

A saída do código acima é 0 – talvez você tenha adivinhado certo, mas adivinhar
não é uma atividade agradável durante a codificação.

A mutabilidade torna o código difícil de raciocinar. Código com mutabilidade


também tem maior chance de erros. E o código com variáveis mutáveis é mais
difícil de paralelizar. Em geral, tente usar val tanto quanto possível em vez de var. Você
verá mais tarde que o Kotlin também adota como padrão val e imutabilidade em diferentes
instâncias.
Machine Translated by Google

Enquanto val em Kotlin é muito parecido com o final do Java, Kotlin – ao contrário do
Java – insiste em marcar variáveis mutáveis com var. Isso torna mais fácil procurar a
presença de var em Kotlin do que procurar a ausência de final em Java. Portanto, no
Kotlin, é mais fácil examinar o código em busca de possíveis erros que possam surgir da
mutabilidade.

Porém, uma palavra de cautela com val : ele apenas torna a variável ou
referência uma constante, não o objeto referenciado. Então val apenas garante a
imutabilidade da referência e não impede a mudança do objeto.
Por exemplo, String é imutável, mas StringBuilder não. Quer você use val ou var, uma
instância de String está protegida contra alterações, mas uma instância de
StringBuilder não. No código a seguir, a variável message é imutável, mas o objeto ao
qual ela se refere é modificado usando essa variável.

val mensagem = StringBuilder( "olá ")

// mensagem = StringBuilder("outra") // ERRO

mensagem.append( "lá")

Resumindo, val concentra-se apenas na variável ou referência em questão, não


naquilo a que se refere. No entanto, prefira val a var sempre que possível.
Machine Translated by Google

Verificação de igualdade aprimorada

Assim como Java, Kotlin também possui dois tipos de verificações de igualdade:

O método equals() em Java, ou operador == em Kotlin, é uma comparação de valores,

chamada igualdade estrutural.

O operador == em Java, ou === em Kotlin, é uma comparação de referências, chamada

igualdade referencial. A igualdade referencial compara referências e retorna verdadeiro


se as duas referências forem idênticas – ou seja, elas se referem exatamente à mesma instância.

O operador === em Kotlin é um equivalente direto do operador == em Java.

Mas o operador de igualdade estrutural == em Kotlin é mais do que o método equals() em Java.

Se você executar str1.equals(str2); em Java, você pode encontrar um NullPointerException se a

referência str1 for nula. Não é assim quando você usa == em Kotlin.

O operador de igualdade estrutural do Kotlin lida com referências nulas com segurança . Vamos

examinar isso com um exemplo:

essência/equalidade.kts

println( "oi" == "oi")


println( "oi" == "Oi")
println( null == "oi ")
println( "oi" == nulo)
println( nulo == nulo)

Se essas comparações fossem feitas com equals() em Java, o resultado líquido teria sido um

NullPointerException em tempo de execução, mas Kotlin lida com os nulos com segurança.

Se os valores mantidos nas duas referências forem iguais, o resultado será verdadeiro e , caso

contrário, falso . Se uma ou outra referência for nula, mas não ambas, o resultado será falso. Se

ambas as referências forem nulas, então o resultado da comparação


Machine Translated by Google

é verdade. Podemos ver isso na saída, mas você também verá um bônus adicional:

verdadeiro

falso
falso
falso
verdadeiro

equality.kts:3:9: aviso: condição 'null == "hi"' é sempre 'false' println(null == "hi")

equality.kts:4:9: aviso: condição '"hi" == null' é sempre 'false' println("hi" == null)

equality.kts:5:9: aviso: condição 'null == null' é sempre 'true' println(null == null)

A saída confirma o comportamento do operador == conforme mencionado. A saída também


mostra outro exemplo dos avisos sensatos do Kotlin – se o resultado da comparação for
sempre um valor esperado, ele exibe um aviso sugerindo que corrigimos o código
para remover a verificação condicional redundante.

Quando == é usado em Kotlin, ele executa as verificações de nulos e, em seguida, chama


o método equals() no objeto.

Você aprendeu a diferença entre usar equals() em Java e == em Kotlin. A seguir,


veremos a facilidade com que podemos criar strings com expressões incorporadas.
Machine Translated by Google

Modelos de string
Em programas, frequentemente criamos strings com valores de expressões incorporados.
Concatenar valores para criar strings usando o operador + torna o código detalhado e difícil
de manter. Os modelos de string resolvem esse problema fornecendo uma solução
elegante.

Dentro de uma string entre aspas duplas, o símbolo $ pode prefixar qualquer variável para
transformá-la em uma expressão. Se a expressão for mais complexa que uma variável
simples, envolva a expressão com ${}.

Um símbolo $ que não é seguido por um nome de variável ou expressão é tratado como literal.
Você também pode escapar do símbolo $ com uma barra invertida para usá-lo como literal.

Aqui está um exemplo com um modelo de string. Além disso, ele contém uma string
simples com símbolos $ incorporados que são usados como literais.

essência/stringtemplate.kts

preço val = 12,25 val


taxRate = 0,08

val output = "O valor $price após impostos chega a $${price * (1 + taxRate)}" val disclaimer
= "O valor
está em US$, isso mesmo em \$only"

println(saída)
println(isenção de responsabilidade)

No modelo de string atribuído à saída, o primeiro símbolo $ é usado como delimitador


para a expressão, o nome da variável, que o segue. O segundo símbolo $ é literal, pois é
seguido por outro $, que não é uma variável ou expressão. O terceiro símbolo $ prefixa uma
expressão encapsulada em {}.
Machine Translated by Google

Os outros símbolos $ no código são usados como literais. Vamos dar uma olhada na
saída do código:

O valor 12,25 após impostos chega a $13,23 O valor


está em US$, isso mesmo em $apenas

O cuidado anterior de preferir val a var também se aplica aqui. Vamos pegar o código
com var que vimos anteriormente e modificá-lo ligeiramente para usar um modelo de string.

essência/mutateconfusion.kts

fator variável = 2

fun doubleIt(n: Int) = n var * fator


message = "O fator é $factor"

fator = 0

println(doubleIt(2))
println(mensagem)

Mais uma vez, não execute o código, mas observe-o e descubra a saída desse código.
Isso corresponde à seguinte saída?

0
O fator é 2

O fator variável dentro da função doubleIt() liga-se à variável fora de seu escopo imediato –

ou seja, em seu escopo léxico. O valor do fator no momento da chamada da função é


usado. O modelo de string, por outro lado, é avaliado quando a variável message é criada,
e não quando seu valor é impresso. Esses tipos de diferenças aumentam a carga cognitiva e
tornam o código difícil de manter e também sujeito a erros. Não há necessidade de torturar
colegas programadores com códigos como este. É desumano. Novamente,
tanto quanto possível, prefira val a var.

A seguir, vamos ver como usar strings brutas para remover alguma confusão e criar
múltiplas linhas de strings.
Machine Translated by Google

Cordas brutas
Lidar com caracteres de escape torna o código confuso. Em vez de usar strings
com escape, no Kotlin podemos usar strings brutas que começam e terminam com
três aspas duplas. Podemos usar strings brutas para colocar qualquer caractere, sem a
necessidade de usar escapes, e também podemos usá-los para criar strings multilinhas.

nenhuma escapatória

Em uma string de escape que começa e termina com aspas duplas simples, não
podemos colocar uma variedade de caracteres, como nova linha ou aspas
duplas, por exemplo, sem usar o caractere de escape \. Mesmo um caso simples
pode ser desagradável de ler, como este:

val escaped = "O garoto perguntou: \"Como vai, $name?\""

Tivemos que escapar das aspas duplas necessárias na string. Quanto mais usamos
strings de escape, mais confuso fica. Em vez de usar strings com escape, no
Kotlin usamos strings brutas. Assim como as strings de escape, as strings brutas
também podem ser usadas como modelos de strings, mas sem a confusão de caracteres
de escape. Aqui está a string de escape acima alterada para string bruta - menos
confusa, mais legível:

val raw = """O garoto perguntou: "Como vai, $name?""""

Use string com escape, ironicamente, quando você não precisa escapar de nada - para
strings pequenas, simples e simples. Se você precisar de algo mais complexo ou
com várias linhas de string, vá para strings brutas.

Strings multilinhas

O infame operador + é frequentemente usado para criar várias linhas de strings e isso
leva a um código desagradável e difícil de manter. Kotlin remove essa
cerimônia com uma string multilinha, que é uma string bruta que contém quebras
de linha. Strings multilinhas também podem atuar como modelos de strings.
Machine Translated by Google

Vamos criar uma string que percorre várias linhas, mas sem o operador + .

essência/memo.kts

val nome = "Eva"

val memo = """Caro $name, um rápido lembrete sobre a festa que


agendamos para a próxima terça-feira no 'Low
Ceremony Cafe' ao meio-dia. | Por favor, planeje..."""

println(memorando)

A string multilinha começa com três aspas duplas, contém a expressão do modelo
de string para avaliar o nome da variável e termina com três aspas duplas. A saída
deste código são várias linhas de string com a expressão incorporada avaliada.

Querida Eve, um rápido lembrete sobre a


festa que marcamos para a próxima terça-feira
no 'Low Ceremony Cafe' ao meio-dia. | Por favor, planeje...

Isso funcionou perfeitamente, mas — sempre há um mas — e se a string multilinha


estivesse dentro de uma função, talvez dentro de um if? O aninhamento bagunçaria as
coisas? Vamos descobrir.

essência/nestedmemo.kts

divertido createMemoFor(nome: String): String {


if (name == "Eve") { val
memo = """Querido $name, um rápido lembrete sobre a festa que
agendamos para a próxima terça-feira no 'Low
Ceremony Cafe' ao meio-dia. | Por favor, planeje..."" "

memorando de devolução

""
retornar
}

println(createMemoFor( "Eva"))
Machine Translated by Google

A função createMemoFor() retorna uma string multilinha se o parâmetro


passado for igual a Eve. Vamos ver o que a saída mostra:

Querida Eve, um rápido lembrete sobre a


festa que marcamos para a próxima terça-
feira no 'Low Ceremony Cafe' ao meio-dia. | Por favor, planeje...

A string resultante preservou o recuo – caramba. Felizmente, não é muito difícil


se livrar dele. Vamos refazer o exemplo:

divertido createMemoFor(nome: String): String {


if (name == "Eve") { val
memo = """Caro $name, um rápido lembrete sobre o
|festa que marcamos para a próxima terça-feira
no 'Low Ceremony Cafe' ao meio-dia. | Por favor, planeje..."""

retornar memo.trimMargin()
}

retornar
""

println(createMemoFor( "Eva"))

Fizemos duas alterações. Primeiro, colocamos um | em cada linha da string


multilinha, começando com a segunda linha. Em segundo lugar, usamos o
método trimMargin() , uma função de extensão (discutiremos isso no Capítulo
12, Fluência em Kotlin), para retirar a margem da string. Sem argumentos,
o método trimMargin() remove os espaços até o início | personagem. O |
personagem que não está na posição de liderança não tem nenhum impacto.
Aqui está a saída que mostra que a correção funcionou.

Querida Eve, um rápido lembrete sobre a


festa que marcamos para a próxima terça-
feira no 'Low Ceremony Cafe' ao meio-dia. | Por favor, planeje...

Se você não quiser usar | como delimitador inicial, porque talvez o seu texto
contenha esse caractere em locais arbitrários, incluindo o primeiro caractere de um
Machine Translated by Google

nova linha, então você pode escolher algum outro caractere - por exemplo, vamos
prosseguir e escolher ~:

val memo = """Caro $name, um rápido lembrete sobre o


~festa que marcamos para a próxima terça-feira
no 'Low Ceremony Cafe' ao meio-dia. | Por favor, planeje..."""

retornar memo.trimMargin( "~")

Na string multilinha usamos ~ como delimitador em vez do padrão |, e na chamada para


trimMargin() passamos aquele delimitador especialmente escolhido como
argumento. A saída desta versão é a mesma onde usamos o delimitador padrão.

Até agora neste capítulo, vimos as melhorias nas expressões e instruções em Kotlin em
comparação com linguagens como Java. Mas Kotlin prefere expressões a declarações.
Vamos discutir isso a seguir.
Machine Translated by Google

Mais expressões, menos declarações


Linguagens como Java, C# e JavaScript têm mais instruções do que expressões
– instrução if, instrução for , try e assim por diante. Por outro lado, linguagens como
Ruby, F#, Groovy, Haskell e muitas outras possuem mais expressões do que
instruções. Vamos discutir o que é melhor antes de discutirmos a preferência de Kotlin.

Embora as declarações sejam predominantes, elas têm um lado negro: não retornam
nada e têm efeitos colaterais. Um efeito colateral é uma mudança de estado: alterar uma
variável, gravar em um arquivo, atualizar um banco de dados, enviar dados para um
serviço web remoto, corromper o disco rígido... As expressões são muito mais legais - elas
retornam um resultado e não têm modificar qualquer estado para ser útil.

Vejamos um exemplo para ver a diferença. Vamos escrever um trecho de código Kotlin
como faríamos em linguagens como Java e C#:

fun canVote(nome: String, idade: Int): String { var


status: String

if (idade > 17)


{ status = "sim, vote" } else
{ status
= "não, volte"
}

return "$nome, $status"


}

println(canVote( "Eva", 12))

O método canVote() usa if como uma instrução. Como as instruções não retornam nada,
a única maneira de obtermos algum resultado útil para processamento posterior é
configurar uma variável mutável e modificar seu valor dentro das ramificações.
Machine Translated by Google

Em Kotlin, entretanto, if é uma expressão. Podemos usar o resultado da chamada para if


para processamento posterior. Vamos retrabalhar o código anterior, para usar if
como uma expressão em vez de uma instrução:

val status = if (age > 17) "sim, por favor vote" else "não, por favor volte"

return "$nome, $status"

Pudemos usar val em vez de var , pois não estamos alterando uma variável.
E pudemos usar inferência de tipo para status, já que o valor é conhecido pela expressão
if . O código é menos barulhento e também menos sujeito a erros.

Kotlin também trata try-catch como uma expressão. A última expressão da parte try se
torna o resultado se não houver exceção; caso contrário, a última instrução dentro do
catch se tornará o resultado.

Aqui está um exemplo de try-catch-finally sendo usado como expressão.

divertido tryExpr(blowup: Boolean): Int


{ return try
{ if (blowup)
{ throw RuntimeException( "fail")
}

2
} catch(ex: Exceção) {
4
} finalmente
{ //...
}
}

println(tryExpr( false)) //2


println(tryExpr( true)) //4

Há uma surpresa, no entanto. Embora o Java trate a atribuição como uma


expressão, o Kotlin não o faz. Se as variáveis a, b e c forem definidas usando var com
Machine Translated by Google

alguns valores inteiros, como 1, 2 e 3 respectivamente, o código a seguir falhará na


compilação em Kotlin:

a = b = c //ERRO

Uma razão para esse comportamento, de não tratar = como uma expressão, é
que o Kotlin permite interceptar get e sets em variáveis com delegados,
como veremos mais adiante neste livro. Se = fosse tratado como uma expressão,
então o encadeamento de atribuições poderia levar a um comportamento inesperado e
complexo que poderia ser confuso e se transformar em uma fonte de erros.
Machine Translated by Google

Empacotando
Kotlin elimina muita cerimônia das tarefas de programação mais fundamentais.
Para a mesma tarefa, muitas vezes você descobrirá que digita muito menos em
Kotlin do que em vários idiomas convencionais. O ponto-e-vírgula é opcional,
as declarações de variáveis aproveitam a inferência de tipos, você não é forçado
a colocar tudo em uma classe ou mesmo em uma função, o tratamento de
exceções não é imposto a você - essas coisas aliviam o fardo da programação. Ao
mesmo tempo, Kotlin tem avisos sensatos para evitar erros comuns. Também
melhora a segurança, solicitando que você escolha entre imutabilidade e
mutabilidade desde o início. Além disso, a verificação de igualdade é
segura para nulos . Modelos de strings e strings multilinhas reduzem o
esforço para criar strings com expressões. E Kotlin fornece mais expressões do
que instruções quando comparado a linguagens como Java, C# e JavaScript.

Nós nos concentramos em expressões e declarações neste capítulo. A seguir,


começaremos a trabalhar com funções.

Copyright © 2020, The Pragmatic Bookshelf.


Machine Translated by Google

Capítulo 3

Trabalhando com Funções


Kotlin não insiste que você crie classes para tudo. Ninguém recebe elogios por
duplicar código, mas reutilizá-lo não significa construir uma hierarquia de classes.
Ao contrário do Java, onde uma classe é a menor peça reutilizável, no Kotlin tanto funções
quanto classes independentes podem ser reutilizadas.

Kotlin adota uma abordagem altamente pragmática para criar código de boa qualidade
– crie pequenas funções independentes e simples onde elas forem suficientes e
transforme seu código em métodos de classes somente quando necessário. Neste
capítulo, focaremos em funções autônomas por dois motivos. Primeiro, porque podemos,
ou seja, em Kotlin podemos criar funções autônomas de nível superior para reutilizar
código e não precisamos desperdiçar nosso tempo e esforço com classes se houver pouco valor.

Segundo, todos os recursos das funções são transferidos diretamente para a


criação de métodos de classes – afinal, os métodos são simplesmente funções
executadas no contexto de classes ou objetos. Portanto, o que você aprende
aqui é útil ao trabalhar com scripts, código processual e código funcional, bem como ao
construir código complexo orientado a objetos.

Com Kotlin você não precisa mascarar funções autônomas como métodos estáticos
de uma classe - ou seja, você não precisa fingir que está fazendo OO para agradar a
linguagem. Você pode criar funções globais de nível superior, como em linguagens como
C e C++, se isso for adequado para sua aplicação. As funções podem residir no nível
superior ou diretamente nos pacotes – você decide onde colocá-las.
Machine Translated by Google

O Kotlin exige que você especifique os tipos de parâmetros para funções, mas você pode
solicitar que ele infira o tipo de retorno para funções de expressão única. Ao chamar
funções, não é necessário passar um argumento para cada parâmetro; em vez
disso, você pode optar por usar argumentos padrão. Você pode usar esse recurso para
evoluir facilmente funções e métodos. Para tornar a chamada aos métodos expressiva,
o Kotlin lhe dá o poder de nomear seus argumentos.
Isso aumenta muito a legibilidade do código. Além disso, você pode passar um número
variável de argumentos para funções sem perder a segurança em tempo de compilação.
Kotlin também tem capacidade de desestruturação, o que fornece uma maneira
altamente concisa de extrair propriedades de objetos em variáveis independentes.

Neste capítulo você aprenderá como trabalhar com funções globais ou autônomas.
Começaremos com as regras do Kotlin para definir funções, veremos como ele trata
funções como expressões e, em seguida, examinaremos muitos recursos úteis, incluindo
argumentos padrão, argumentos nomeados, definição de número variável de
argumentos, o operador spread e uso de desestruturação. Usando esses recursos,
você pode criar código altamente expressivo, fácil de ler e mais flexível de manter. Se
você estiver mais interessado em escrever código orientado a objetos, tenha
certeza de que os conceitos aprendidos aqui também se aplicam a métodos de classes.

Vamos nos divertir com funções.


Machine Translated by Google

Criando Funções
Criar funções e métodos em Kotlin é totalmente diferente de criar métodos em Java. A maior
flexibilidade que o Kotlin oferece elimina cerimônias desnecessárias na criação de funções.
Vamos começar com funções curtas, explorar a inferência de tipos e, em seguida, examinar
a definição de parâmetros e funções multilinhas.

Funções do KISS

Kotlin segue o mantra “Keep it simple, estúpido” – o princípio KISS – para definir definições. Funções
pequenas devem ser simples de escrever, sem ruído, sem complicações. Aqui está uma das
funções mais curtas que você pode escrever em Kotlin, seguida de uma chamada para ela.

funções/kiss.kts

saudação divertida() = "Olá"

println(saudação())

As declarações de função começam com a palavra-chave fun – Kotlin quer que você se

lembre de se divertir sempre que olhar para uma função ou método. O nome da função é seguido
por uma lista de parâmetros, que pode estar vazia. Se a função for uma função de expressão
única, que é muito curta, separe o corpo da declaração usando o operador = em vez de usar a
sintaxe do bloco {} . Para funções curtas, o tipo de retorno pode ser inferido. Além disso, a

palavra-chave return não é permitida para funções de expressão única, que são funções sem
corpo de bloco.

Execute este script para ver Kotlin cumprimentá-lo:

Olá

Vamos examinar o que a função acima realmente retorna.


Machine Translated by Google

Tipo de retorno e inferência de tipo


A função greet() retorna uma String, mas não especificamos isso explicitamente.
Isso ocorre porque o Kotlin pode inferir o tipo de retorno de funções com corpo sem bloco,
ou seja, funções sem {}. A inferência do tipo de retorno acontece em tempo de
compilação. Vamos verificar isso cometendo um erro no código:

saudação divertida() = "Olá"

val mensagem: Int = greet() //ERRO //


incompatibilidade de tipo: o tipo inferido é String, mas Int era esperado

Com base no contexto, Kotlin determina que greet() está retornando uma String.
Estamos atribuindo isso a uma mensagem variável do tipo Int, o que é proibido, e o
código não será compilado.

A inferência de tipo é segura de usar e a verificação de tipo acontece em tempo de


compilação; use-o para APIs internas e onde as funções são uma única expressão
separada por =. Mas se a função for para uso externo ou for mais complexa, especifique
explicitamente o tipo de retorno. Isso ajudará você e os usuários de suas funções a verem
claramente o tipo de retorno. Também evitará surpresas que possam surgir se o
tipo de retorno for inferido e a implementação for alterada para retornar
um tipo diferente.

Kotlin inferirá o tipo de retorno das funções somente quando o corpo da função for uma
expressão única e não um bloco.

Vamos modificar a função greet() para especificar explicitamente o tipo de retorno.

saudação divertida(): String = "Olá"

O tipo de retorno é prefixado com : e vai logo após a lista de parâmetros.


A palavra-chave return ainda não é permitida porque o corpo da função é uma expressão
única e não um bloco.

Deixe de fora o tipo de retorno se for óbvio, especifique-o caso contrário.


Machine Translated by Google

E se a função não retornar nada? Vamos visitar essas incômodas funções vazias a
seguir.

Todas as funções são expressões


Como você viu em Mais Expressões, Menos Declarações, Kotlin favorece
expressões em vez de declarações. Com base nesse princípio, as funções devem
ser tratadas como expressões em vez de instruções, e podemos compor uma sequência
de chamadas para invocar um método no valor de retorno de cada uma.

Kotlin usa um tipo especial chamado Unit que corresponde ao tipo void de Java. O
nome Unit vem da teoria dos tipos e representa um singleton que não contém nenhuma
informação. Você pode usar Unit de forma consistente para especificar que não está
retornando nada útil. Além disso, Kotlin inferirá o tipo como Unit se a função não retornar
nada. Vamos dar uma olhada nesta inferência primeiro.

funções/inferunit.kts

divertido dizerOlá() = println( "Bem, olá")

val mensagem: String = sayHello() //ERRO //


incompatibilidade de tipo: o tipo inferido é Unidade, mas String era esperado

A função sayHello() imprime uma mensagem na saída padrão usando println(), que
sabemos ser uma função void em Java, mas retorna Unit em Kotlin. Usamos
inferência de tipo para o tipo de retorno de sayHello(), mas tenha certeza de que ela é
inferida como Unit. Verificamos o tipo inferido atribuindo o resultado de sayHello() a uma
variável do tipo String, e isso falhará na compilação devido à incompatibilidade de tipo.

Em vez de usar inferência de tipo, podemos especificar explicitamente Unit como o tipo
de retorno também. Vamos alterar sayHello() para especificar o tipo de retorno e
então atribuir o resultado a uma variável do tipo Unit:

funções/especificarunit.kts
Machine Translated by Google

divertido dizerOlá(): Unit = println( "Bem, olá")

mensagem val : Unidade = sayHello()

println( "O resultado de sayHello é $message")

Como até mesmo funções void retornam Unit em Kotlin, todas as funções podem ser
tratadas como expressões e podemos invocar métodos nos resultados de qualquer função.
Por sua vez, o tipo Unit possui os métodos toString(), equals() e hashCode() .

Embora não seja muito útil, você pode invocar qualquer um desses métodos. Por
exemplo, no código anterior passamos a variável message , que é do tipo Unit, para println(),
e que chama internamente o método toString() de Unit. Vamos dar uma olhada na saída:

Bem, olá O
resultado de sayHello é kotlin.Unit

O método toString() de Unit apenas retorna uma String com valor kotlin.Unit, o nome
completo da classe.

Como todas as funções retornam algo útil, ou pelo menos uma unidade , todas elas servem
como expressões e o resultado pode ser atribuído a uma variável ou usado para
processamento posterior.

As funções que usamos até agora neste capítulo não aceitam nenhum parâmetro, mas na
realidade as funções normalmente aceitam parâmetros. Vamos agora nos concentrar
na definição de parâmetros e na passagem de argumentos para funções.

Definindo Parâmetros
Algumas linguagens como Haskell e F# podem mergulhar em funções e inferir os tipos de
parâmetros. Pessoalmente, não sou fã disso; alterar a implementação de uma função
pode resultar na alteração dos tipos dos parâmetros. Isso é perturbador para mim.
Kotlin insiste em especificar os tipos de parâmetros para funções e métodos. Forneça o tipo
do parâmetro logo após o nome do parâmetro, separado por :.
Machine Translated by Google

Vamos alterar a função greet() para receber um parâmetro do tipo String .

funções/passingarguments.kts

saudação divertida (nome: String): String = "Olá $nome"

println(greet( "Eva")) //Olá Eva

A especificação de tipo em Kotlin tem a forma consistente candidate: Type, onde o


candidato pode ser um dos seguintes: declaração de variável usando val ou var,
declaração de função para especificar o tipo de retorno, parâmetros de função
e um argumento passado para o bloco catch .

Embora o tipo do nome do parâmetro seja obrigatório, podemos omitir o tipo de retorno
se quisermos que o Kotlin infira o tipo de retorno. Se você tiver mais de um parâmetro,
liste-os separados por vírgulas entre parênteses.

Você viu em Prefer val over var, que devemos preferir a imutabilidade à mutabilidade
e que o Kotlin força você a escolher entre val e var ao definir variáveis locais. Mas ao
definir a função greet() , não especificamos val ou var para o parâmetro. Isso tem um
bom motivo.

Effective Java, Third Edition [Blo18] aconselha os programadores a usarem final e


preferirem a imutabilidade tanto quanto possível. Kotlin não quer que façamos uma
escolha aqui para parâmetros de função e método; decidiu que modificar parâmetros
passados para funções é uma má ideia. Você não pode dizer val ou var para
parâmetros – eles são implicitamente val, e qualquer esforço para alterar os valores dos
parâmetros dentro de funções ou métodos resultará em erros de compilação.

Vimos funções realmente curtas até agora. Vejamos como escrever funções mais complexas.

Funções com corpo de bloco


Machine Translated by Google

Quando uma função é pequena, uma única expressão, podemos separar o corpo da função da
declaração usando o operador = . Se a função for mais complexa que isso, coloque o corpo em um

bloco {} e não use =. Você deve especificar o tipo de retorno para qualquer função com corpo

de bloco; caso contrário, o tipo de retorno será inferido como Unidade.

Vamos escrever uma função que retorne o máximo entre os números em um determinado
variedade.

funções/multilinefunction.kts

fun max (números: IntArray): Int { var


large = Int.MIN_VALUE

for (número em números)


{ grande = if (número > grande) número senão grande
}

retornar grande
}

println(max(intArrayOf(1, 5, 2, 12, 7, 3))) //12

A função max() usa um array como parâmetro, especifica Int como o tipo de retorno e tem um

corpo envolvido em um bloco {}. Neste caso, o tipo de retorno não é opcional – você deve especificá-

lo, pois o corpo da função é um bloco.


Além disso, a palavra-chave return é obrigatória.

Uma palavra de cautela: não use = seguido por um corpo {} de bloco . Se você especificar

explicitamente o tipo de retorno e segui-lo com o corpo, o compilador =, e então um bloco

gerará um erro.

E se omitirmos o tipo de retorno, mas usarmos = e depois um corpo de bloco em vez de uma única

expressão? Por exemplo, e se escrevermos algo como o seguinte?

divertido notReally() = { 2 }
Machine Translated by Google

Kotlin não inferirá o tipo de retorno entrando no bloco de código. Porém, ele assumirá que
todo o bloco seja uma expressão lambda ou uma função anônima — um tópico que
abordaremos mais adiante neste livro. Kotlin acha que notReally() é uma função que retorna
uma expressão lambda – opa.

Por uma questão de diversão, uma definição reconhecidamente distorcida de diversão, vamos
explorar o efeito de usar = com um bloco, mas sem um tipo de retorno.

funções/caveat.kts

divertido f1()
= 2 divertido f2()
= { 2 } divertido f3(fator: Int) = { n: Int -> n * fator }

println(f1()) //2
println(f2()) //() -> kotlin.Int println(f2()
()) //2 println(f3(2)) //
(kotlin.Int) - > kotlin.Int println(f3(2)(3)) //6

A função f1() é inferida para retornar um Int. Mas Kotlin inferiu que a função f2() está

retornando uma expressão lambda que não aceita parâmetros e retorna um Int. Da mesma
forma, inferiu que a função f3() está retornando um lambda que pega Int e retorna Int.

É altamente improvável que alguém que escreve esse código tenha muitos amigos – não
adianta escrever um código como esse e passar o resto da vida sozinho. Se você deseja
criar funções que retornem lambdas, veremos maneiras melhores de fazer isso mais tarde.
Resumindo, não misture = com o corpo do bloco.

Você sabe criar funções; a seguir, veremos como podemos evoluir facilmente as funções
existentes no Kotlin.
Machine Translated by Google

Argumentos padrão e nomeados


A sobrecarga de funções é comum em Java e é a maneira de criar funções que
podem receber diferentes números e tipos de argumentos. Essa também é uma opção no
Kotlin, mas o recurso de argumentos padrão é uma maneira mais simples e melhor de evoluir
funções, embora exija recompilação, pois quebra a compatibilidade binária. Além disso,
argumentos nomeados são uma ótima maneira de criar código legível. Vamos nos
concentrar nesses dois recursos agora.

Evoluindo funções com argumentos padrão


Dê uma olhada rápida na função greet() que escrevemos anteriormente, repetida aqui
por conveniência.

saudação divertida (nome: String): String = "Olá $nome"

println(greet( "Eva")) //Olá Eva

A função greet() tem uma string codificada "Hello", mas e se quisermos fornecer
flexibilidade ao chamador da função para fornecer uma gentileza de sua escolha?

Se adicionarmos um novo parâmetro à função, qualquer código existente que chame a


função será quebrado porque ficará tímido em relação ao parâmetro tão necessário, embora
novo. Em linguagens como Java usamos sobrecarga para esse propósito, mas isso pode
levar à duplicação de código. Kotlin facilita essa tarefa com argumentos padrão.

Um argumento padrão é um parâmetro que assume um valor padrão logo após a


declaração. Se o chamador não passar um valor para esse parâmetro, o valor padrão
será usado. Especifique o nome do parâmetro, dois pontos, tipo, seguido pela
atribuição ao valor padrão, usando =. Vamos alterar o método greet para assumir um
parâmetro adicional, mas com um valor padrão.

funções/defaultarguments.kts
Machine Translated by Google

saudação divertida (nome: String, msg: String = "Olá"): String = "$msg $nome"

println(greet( "Eve")) //Olá Eve


println(greet( "Eve", "Howdy")) // Olá Eve

O código existente que chama greet() com apenas um argumento para name
continua funcionando. Qualquer nova chamada para greet() pode passar um argumento, para
nome, ou dois argumentos, para nome e mensagem. Na primeira chamada, como msg
não recebe um valor, o argumento padrão Hello é usado. Na segunda chamada, o
argumento fornecido Howdy é usado e o argumento padrão é ignorado.

Em greet(), o parâmetro com argumento padrão é colocado após o parâmetro regular –


ou seja, aquele sem argumento padrão. Você pode estar se perguntando se faz sentido
trocar a ordem de aparição. Sim, mas com consequências:

Como um valor será necessário para o parâmetro regular, o chamador será forçado a
fornecer um valor para o parâmetro com argumento padrão também – isso anula o
propósito de ter o argumento padrão.

O chamador pode ignorar o parâmetro padrão se usar argumentos nomeados —


veremos isso em Melhorar a legibilidade com argumentos nomeados.

Um parâmetro com argumento padrão pode preceder um último parâmetro que


representa uma expressão lambda — veremos o benefício disso em Usar Lambda
como último parâmetro.

Resumindo, para tornar os argumentos padrão eficazes, use-os nos parâmetros


finais e siga-os, opcionalmente, apenas com parâmetros para expressões lambda.

O argumento padrão não precisa ser literal; pode ser uma expressão.
Além disso, você pode calcular os argumentos padrão para um parâmetro usando os
parâmetros à sua esquerda.
Machine Translated by Google

O argumento padrão usado na função greet() possui um valor codificado.

Vamos mudar isso para usar o parâmetro à sua esquerda:

funções/defaultcompute.kts

saudação divertida (nome: String, msg: String = "Oi ${nome.length}") = "$msg $nome"

println(greet( "Scott", "Howdy")) // Olá Scott


println(greet( "Scott")) //Olá 5 Scott

Mais uma vez, quando dois argumentos são passados para greet(), o argumento padrão é ignorado;

não é computado. Por outro lado, quando apenas o valor do parâmetro name é passado, então o valor
do parâmetro msg é calculado a partir da expressão do argumento padrão. Na segunda chamada a

greet(), passamos apenas o nome e o resultado; msg é calculado com base no valor do parâmetro

name – um high five geeky para o bom amigo Scott.

Neste exemplo, trocar a posição de name e msg resultará em um erro de compilação, pois

name não foi inicializado na expressão de argumento padrão - outro motivo para colocar

parâmetros com argumentos padrão nas posições finais.

Melhore a legibilidade com argumentos nomeados


O código é escrito uma vez, mas lido e atualizado muitas vezes. Qualquer coisa que possamos fazer
para reduzir a carga sobre os leitores é um passo bem-vindo. Em uma chamada como
greet("Scott", "Howdy") não é difícil supor o que os argumentos representam.

Mas você pode se deparar com uma chamada como esta:

funções/namedarguments.kts

createPerson( "Jake", 12, 152, 43)

Você pode estar se perguntando o que esses números significam, e isso certamente não é
divertido quando se lida com prazos iminentes. Você terá que mudar de contexto e consultar a
documentação da função ou sua declaração para encontrar o

significado desses números mágicos.


Machine Translated by Google

funções/namedarguments.kts

fun createPerson(nome: String, idade: Int = 1, altura: Int, peso: Int) {


println( "$nome $idade $altura $peso")
}

Código mal escrito pode transformar o ser humano mais educado em um péssimo xingador
– a legibilidade é importante. Kotlin é uma linguagem de fluência, e esse princípio também brilha
nas chamadas de métodos.

Sem alterar nada na forma como uma função é definida, você pode tornar as chamadas aos métodos mais

legíveis, com pouco esforço. É aqui que entram os argumentos nomeados.

Vamos tornar a chamada para createPerson() legível:

funções/namedarguments.kts

createPerson(nome = "Jake", idade = 12, peso = 43, altura = 152)

Isso é muito melhor – sem suposições e sem preocupações sobre o que esses parâmetros
significam. Você pode atribuir um valor ao nome de um parâmetro ali mesmo na
chamada de função. Mesmo que a função tenha peso como último parâmetro, não é necessário
que seja o último na chamada; argumentos nomeados podem ser colocados em qualquer
ordem.

A confusão neste código está entre os diferentes valores inteiros; o valor do nome em
createPerson é intuitivo. Podemos colocar argumentos nomeados após argumentos
posicionais, conforme mostrado nos dois exemplos a seguir:

funções/namedarguments.kts

createPerson( "Jake", idade = 12, peso = 43, altura = 152)

funções/namedarguments.kts

createPerson( "Jake", 12, peso = 43, altura = 152)


Machine Translated by Google

Embora a última seja uma sintaxe Kotlin válida, do ponto de vista da legibilidade, pode ser
melhor usar o argumento nomeado para a idade também.

Como age tem um argumento padrão, podemos deixá-lo de fora se usarmos valores
nomeados para todos os outros parâmetros ou argumentos posicionais para todos os
parâmetros à sua esquerda e argumentos nomeados para todos os outros parâmetros.

Por exemplo, as duas chamadas a seguir que omitem o argumento da idade são válidas:

funções/namedarguments.kts

createPerson(peso = 43, altura = 152, nome = "Jake")

createPerson( "Jake", peso = 43, altura = 152)

Argumentos nomeados tornam as chamadas de método legíveis e também eliminam


possíveis erros ao adicionar novos parâmetros a funções existentes. Use-os quando os
parâmetros passados não forem óbvios. Vamos agora voltar nossa atenção para dois outros
recursos do Kotlin que podem reduzir o ruído nas chamadas de métodos.
Machine Translated by Google

vararg e propagação
Funções como println() aceitam um número variável de argumentos. O recurso
vararg do Kotlin fornece uma maneira segura de criar funções que podem receber
um número variável de argumentos. O operador spread é útil para explodir ou espalhar
valores em uma coleção como argumentos discretos. Veremos primeiro o vararg e o
spread a seguir.

Número variável de argumentos


Em Funções com corpo de bloco, escrevemos uma função max() que utiliza um array
de números. Na chamada da função, como esperado, passamos um array de valores.
Se já temos um array de valores, então não é grande coisa; mas se tivermos um conjunto
discreto de valores, para chamar a função teremos que criar um array temporário desses
valores e depois passar esse array. Tedioso.

No Kotlin, as funções podem receber um número variável de argumentos. Vamos converter


a função max() para ser mais flexível para quem chama.

funções/vararg.kts

fun max ( números vararg : Int): Int { var


large = Int.MIN_VALUE

for (número em números)


{ grande = if (número > grande) número senão grande
}

retornar grande
}

Comparada com a função max() que escrevemos anteriormente, esta versão possui
duas alterações, ambas na lista de parâmetros. Primeiro, os números dos parâmetros
são prefixados com a palavra-chave vararg. Segundo, o tipo do parâmetro é especificado como Int
Machine Translated by Google

em vez de IntArray. O tipo real dos números dos parâmetros é uma matriz; o vararg
anota o parâmetro como uma matriz do tipo especificado.

Vamos fazer algumas chamadas para a função, passando alguns valores discretos.

funções/vararg.kts

println(max(1, 5, 2)) //5


println(max(1, 5, 2, 12, 7, 3)) //12

Isso funcionou muito bem — podemos passar qualquer número de argumentos e a


verificação de tipo do Kotlin garantirá que os diferentes argumentos sejam do tipo correto.

A função max() utiliza apenas um parâmetro, mas você pode usar vararg quando uma
função também utiliza mais de um parâmetro. Mas apenas um parâmetro pode ser
anotado como vararg.

Aqui está uma função que recebe dois parâmetros, mas apenas o último é marcado
como vararg.

funções/mixvararg.kts

divertido greetMany(msg: String, nomes vararg : String)


{ println( "$msg ${names.joinToString(", ")}")
}

greetMany( "Olá", "Tom", "Jerry", "Spike") // Olá Tom, Jerry, Spike

Na chamada, o primeiro argumento é vinculado ao primeiro parâmetro e os argumentos


restantes são passados para o parâmetro vararg .

O tipo do parâmetro vararg pode ser independente do tipo de qualquer outro parâmetro
que a função aceita.

O parâmetro vararg não precisa ser o parâmetro final, mas eu recomendo fortemente que
seja. Considere a seguinte versão da função greetMany() :
Machine Translated by Google

divertido greetMany( nomes vararg : String, msg: String)


{ println( "$msg ${names.joinToString(", ")}")
}

Ao chamar a função, se você passar qualquer número de argumentos String sem


nome , o compilador assumirá que todos eles são para o parâmetro vararg .
Para saber que um valor é para o parâmetro msg , você terá que usar um argumento
nomeado, assim:

greetMany( "Tom", "Jerry", "Spike", msg = "Olá") // Olá Tom, Jerry, Spike

Se você anotar um parâmetro não final com vararg, o chamador será forçado a usar
argumentos nomeados.

Aqui estão algumas recomendações sobre onde colocar o parâmetro vararg :

Coloque-o na posição final para que os chamadores não sejam forçados a usar
argumentos nomeados.
Coloque-o antes do último parâmetro se for esperado que o último argumento seja
uma expressão lambda — exploraremos isso mais adiante neste livro.

Vimos como o Kotlin facilita a passagem de um número variável de argumentos, mas e


se já tivermos um array com valores? O operador de spread vem em socorro nesse
caso.

Operador de propagação

Dê uma outra olhada na função max() com vararg no exemplo anterior - ela tornou mais
fácil passar diferentes números de argumentos. Às vezes, porém, podemos querer
passar valores que estão em um array ou lista para uma função com vararg. Mesmo que
a função possa receber um número variável de argumentos, não podemos enviar
diretamente um array ou uma lista. É aqui que entra o operador spread. Para ver um
exemplo de uso desse operador, vamos começar com a seguinte instância:

funções/vararg.kts
Machine Translated by Google

valores val = intArrayOf(1, 21, 3)

O vararg implica que podemos passar qualquer número de argumentos para este único
parâmetro. Mas se passarmos um array como argumento, obteremos um erro:

println(max(values)) //ERRO //
incompatibilidade de tipo: o tipo inferido é IntArray, mas Int era esperado

Embora internamente o tipo de parâmetro vararg seja um array, Kotlin não quer que
passemos um argumento de array. Só aceitará vários argumentos do tipo vararg
especificado .

Para usar os dados do array, podemos tentar o seguinte:

funções/vararg.kts

println(max(valores[0], valores[1], valores[2])) //SMELLY, não

Mas isso é prolixo e você nunca será capaz de mostrar esse código com orgulho para
ninguém, nem mesmo para a mãe.

Onde o parâmetro é anotado como vararg, você pode passar um array – do tipo correto, é
claro – prefixando-o com o operador spread *. Vamos passar os valores do array como
argumento para o parâmetro numbers de max():

funções/vararg.kts

println(max(*valores)) //21

Isso é muito melhor. Ao colocar um * na frente do argumento, você está pedindo ao Kotlin
para espalhar os valores nessa matriz como valores discretos para o parâmetro vararg .
Não há necessidade de escrever código detalhado; a combinação de vararg e spread
restaura a harmonia.

Se tivermos um array, podemos usar spread, mas muitas vezes trabalhamos com listas em
vez de arrays. Se quisermos passar uma lista de valores, não podemos usar o operador
spread na lista diretamente. Em vez disso, temos que converter a lista em um array,
Machine Translated by Google

do tipo desejado e depois use spread. Aqui está um exemplo de como isso ficaria:

funções/vararg.kts

println(max(*listOf(1, 4, 18, 12).toIntArray()))

Se os elementos na lista e o tipo de vararg forem de um tipo diferente de Int, use o


método to...Array() apropriado de List<T> para converter em uma matriz do tipo
desejado.
Machine Translated by Google

Desestruturação

Estruturar, ou construir, é criar um objeto a partir de valores em diferentes variáveis. A


desestruturação é o oposto – extrair valores em variáveis de dentro de um objeto existente.
Este recurso é útil para remover código repetitivo e barulhento. Kotlin tem capacidade de
desestruturação semelhante a linguagens como JavaScript. Mas, diferentemente do
JavaScript, a desestruturação em Kotlin é baseada na posição das propriedades em vez dos
nomes das propriedades.

Vamos começar com um trecho de código detalhado e depois refatorá-lo, usando


desestruturação, para torná-lo conciso. Triple é uma classe da biblioteca padrão Kotlin que

representa uma tupla. Veremos isso mais detalhadamente em Usando Par e Triplo. Por
enquanto, usaremos Triple para retornar um grupo de três valores:

funções/desestruturação.kts

divertido getFullName() = Triple( "John", "Quincy", "Adams")

Aqui está uma chamada tradicional e chata para a função acima, para receber o resultado e
atribuir três variáveis diferentes.

funções/desestruturação.kts

val resultado = getFullName() val


primeiro = resultado.primeiro
val meio = resultado.segundo val
último = resultado.terceiro

println( "$primeiro $meio $último") // John Quincy Adams

Isso exigiu várias linhas de código e algumas operações de ponto. Mas quando o tipo de
retorno de uma função é Par, Triplo ou qualquer classe de dados, podemos usar a

desestruturação para extrair os valores em variáveis, de forma elegante e concisa.


Vamos reescrever o código, desta vez para usar a desestruturação.
Machine Translated by Google

funções/desestruturação.kts

val (primeiro, meio, último) = getFullName()

println( "$primeiro $meio $último") // John Quincy Adams

Quatro linhas reduzidas a uma única linha de código concisa. Parece que a função
getFullName() retornou repentinamente vários valores – uma bela ilusão.
As três variáveis imutáveis primeiro, meio e último são definidas nessa linha e recebem

imediatamente as três propriedades do resultado Triplo, na ordem primeiro, segundo e terceiro,

respectivamente. Na realidade, isso funciona porque a classe Triple possui métodos especializados

para auxiliar na desestruturação; você aprenderá sobre isso mais adiante no livro. A ordem em que as

propriedades são desestruturadas é a mesma ordem em que as propriedades são


inicializadas no construtor do objeto de origem.

Suponha que não nos importamos com uma das propriedades do objeto que está sendo
retornada. Por exemplo, se não quisermos o nome do meio, podemos usar um sublinhado
(_) para ignorá-lo.

funções/desestruturação.kts

val (primeiro, _, último) = getFullName()

println( "$primeiro $último") // John Adams

Da mesma forma, você pode pular mais de uma propriedade usando vários _s, como
então:

funções/desestruturação.kts

val (_, _, último) = getFullName()

println(último) //Adams

Você pode colocar _ em qualquer posição que deseja ignorar. Se você quiser parar em uma
determinada posição e ignorar o resto, você não precisa preencher todos
Machine Translated by Google

espaços restantes com _s. Por exemplo, para obter apenas o nome do meio podemos escrever:

funções/desestruturação.kts

val (_, meio) = getFullName()

println(meio) //Quincy

Além de usar a desestruturação quando o tipo de retorno é uma classe de dados, você também
pode usar a desestruturação para extrair chave e valor das entradas do Mapa — consulte

Usando o Mapa.

Se você está curioso para saber como a desestruturação funciona nos bastidores e quais são
esses métodos especiais aos quais mencionei, fique ligado; revisitaremos a destruição e exploraremos
mais detalhadamente em Classes de dados.
Machine Translated by Google

Empacotando
Kotlin não força você a criar métodos; você também pode criar funções de nível
superior. Isso abre mais algumas opções de design em Kotlin do que em Java – os
aplicativos não precisam ser compostos apenas por objetos, eles também podem ser
compostos por funções. Isso permite criar código processual, orientado a objetos ou
de estilo funcional, o que for melhor em um determinado contexto. O compilador pode
inferir tipos de retorno para funções sem bloco de expressão única. Os tipos de
parâmetros são sempre obrigatórios e isso é bom.

Os argumentos padrão facilitam muito a extensão de funções em Kotlin e reduzem


a necessidade de sobrecarregar funções. Os parâmetros vararg oferecem a flexibilidade
de passar um número discreto de argumentos com segurança de tipo, e o operador
spread oferece uma ótima maneira de explodir um argumento de array em um
parâmetro vararg . Usar argumentos nomeados é uma ótima maneira de tornar o
código legível; é uma maneira de escrever código autodocumentado. Finalmente,
a desestruturação é um recurso que pode reduzir o ruído no código e torná-lo altamente conciso.

No próximo capítulo, aprenderemos como iterar um intervalo de valores e processar


dados usando o recurso de correspondência de argumentos do Kotlin.

Copyright © 2020, The Pragmatic Bookshelf.


Machine Translated by Google

Capítulo 4

Iteração Externa e Argumento


Coincidindo

Conte quantas vezes você usou loops for em seu código. Chocante.
Algo que é tão amplamente utilizado e fundamental como a iteração deve ser fluente,
conciso, fácil de escrever e fácil de entender. No entanto, em linguagens semelhantes
a C, os loops for têm sido bastante primitivos e detalhados. Não é assim em Kotlin.

Kotlin fornece iteradores externos, usados no estilo imperativo de programação, e


iteradores internos, usados no estilo funcional. Com a iteração externa, você, como
programador, controla explicitamente a sequência da iteração, por exemplo, com i++, i-- e
assim por diante. A iteração interna se encarrega do sequenciamento e permite que os
programadores se concentrem nas ações ou cálculos de cada iteração,
resultando em menos código e menos erros.
Exploraremos os benefícios da iteração interna no Capítulo 10, Programação
Funcional com Lambdas, mas neste capítulo vamos nos concentrar na fluência que o
Kotlin fornece para trabalhar com a iteração externa comum.

Neste capítulo, você aprenderá os recursos do Kotlin para iterar de maneira concisa e
elegante em intervalos de valores e em objetos em coleções. Você verá que o código
que você escreve para filtrar dados e tomar decisões não precisa ser uma série de blocos
if-else repetidos . A elegante correspondência de argumentos de Kotlin
Machine Translated by Google

recursos removerão muitos detritos e tornarão a lógica de decisão altamente transparente


para o leitor.

Depois de adquirir os recursos fornecidos em Kotlin, você nunca mais vai querer voltar
às antigas formas de iteração. A sintaxe concisa, agradável e expressiva irá mantê-lo em
movimento, motivado e focado no problema em questão. Como resultado, você escreverá
menos código para implementar suas regras de negócios.

Como frequentemente trabalhamos com intervalos de valores, você pode usar prontamente
as classes e funções do pacote kotlin.ranges para iterar bem, transformando a tarefa
de escrever esse código em uma experiência agradável. O loop for aprimorado não serve
apenas para um intervalo de valores; você também pode usá-lo para iterar
valores em uma coleção.

Também veremos a elegante sintaxe de correspondência de argumentos e a poderosa


expressão when , que evitará que você se afogue em códigos profundamente aninhados.
Esta se tornará sua sintaxe ideal para realizar diferentes ações em diferentes dados.

1, 2, 3… vamos começar a iteração.

Você também pode gostar