Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Swift
Code

Swift from Scratch: Closures

by
Difficulty:BeginnerLength:MediumLanguages:
This post is part of a series called Swift From Scratch.
Swift From Scratch: Function Parameters, Types, and Nesting
Swift From Scratch: An Introduction to Classes and Structures

Portuguese (Português) translation by David Batista (you can also view the original English article)

Se você trabalhou com blocos em C/Objective-C ou lambdas em Ruby, então você não terá problemas para entender o conceito de closures. Closures são nada mais do que blocos de funcionalidade que você pode passar durante seu código.

Na verdade, nós já trabalhamos com closures nos dois artigos anteriores. É isso mesmo. Funções são closures também. Vamos começar com o básico e inspecionar a anatomia de uma closure.

1. O que é uma closure?

Como eu disse, uma closure é um bloco de funcionalidade que você pode passar durante seu código. Você pode passar uma closure como um argumento de uma função ou você pode armazená-la como uma propriedade de um objeto. Closures tem muitos casos de uso.

O nome closure (fecho) sugere uma das características chave das closures. Uma closure captura as variáveis e constantes do contexto no qual ela está definida. Isto é por vezes referido como closing over (fechando sobre) as variáveis e constantes. Nós vamos olhar para captura de valor mais detalhadamente no final deste artigo.

Flexibilidade

Você já aprendeu que funções podem ser incrivelmente poderosas e flexíveis. Como as funções são closures, closures são igualmente flexíveis. Neste artigo, você vai descobrir quão flexível e poderosa elas são.

Gerenciamento de memória

A linguagem de programação C tem um conceito similar, blocos. As closures em Swift, no entanto, tem alguns benefícios. Uma das vantagens chave das closures em Swift é que o gerenciamento de memória é algo que você, o desenvolvedor, não tem que se preocupar.

Até reter ciclos, os quais não são incomuns em C/Objective-C, são manipulados pelo Swift. Isto irá reduzir vazamentos de memória difíceis de encontrar ou falhas devido a ponteiros inválidos.

2. Sintaxe

A sintaxe básica de uma closure não é difícil e irá lembrá-lo de funções encadeadas e globais, que abordamos anteriormente nesta série. Dê uma olhada no exemplo a seguir.

A primeira coisa que você notará é que a closure inteira é cercada por chaves. Parâmetros do closure são cercadas por parênteses, separadas do tipo de retorno pelo símbolo ->. A closure acima aceita um argumento, a, do tipo Int e retornar um Int. O corpo da closure começa depois da palavra-chave in.

Closures nomeadas, ou seja, funções encadeadas e globais, parecem um pouco diferente. O exemplo a seguir deve ilustrar as diferenças.

As diferenças mais importantes são o uso da palavra-chave func e a posição dos parâmetros e tipo de retorno. Uma closure começa e termina com chaves, envolvendo os parâmetros, tipo de retorno e o corpo da closure. Apesar dessas diferenças, lembre-se que toda função é uma closure. Mas nem toda closure é uma função.

3. Closures como parâmetros.

Closures são poderosas e o exemplo a seguir ilustra como elas podem ser úteis. No exemplo, criamos um array de estados. Chamamos a função map no array para criar um novo array que contém apenas as duas primeiras letras de cada Estado com uma string em maiúsculas.

O método ou função map é comum em muitas linguagens de programação e bibliotecas, como jQuery, PHP e Ruby. No exemplo acima, a função map é chamada no array de states, transforma o seu conteúdo e retorna um novo array que contém os valores transformados.

Inferência de tipo

Anteriormente nesta série, aprendemos que o Swift é bastante inteligente. Vamos ver exatamente inteligente quanto. A array de Estados é um array de strings. Como chamamos a função map no array, o Swift sabe que o argumento state é do tipo String. Isto significa que podemos omitir o tipo, conforme mostrado no exemplo abaixo atualizado.

Existem mais algumas coisas que podemos omitir do exemplo acima, originando a seguinte linha de comando.

Deixe-me explicar o que está acontecendo. O compilador pode deduzir que retornaremos uma string da closure que passamos para a função map, o que significa que não há nenhuma razão para incluí-lo na definição de expressão da closure. Só podemos fazer isso se o corpo da closure inclui uma única instrução. Nesse caso, podemos colocar essa declaração na mesma linha como na definição da closure, conforme mostrado no exemplo acima. Como não há nenhum tipo de retorno na definição e não precede o símbolo -> no tipo de retorno, podemos omitir os parênteses delimitador dos parâmetros da closure.

Nomes de argumento abreviados

Porém não para por aqui. Nós podemos fazer uso de nomes de argumento abreviados para simplificar ainda mais a expressão da closure acima. Ao usar uma expressão da closure inline, como no exemplo acima, podemos omitir a lista de parâmetros, incluindo a palavra-chave in que separa os parâmetros do corpo de encerramento.

No corpo da closure, referenciamos o argumento usando o nome do argumento abreviado que o Swift nos fornece. O primeiro argumento é referenciado por $0, o segundo por $1, etc.

No exemplo atualizado a seguir, eu omiti a lista de parâmetros e a palavra-chave in, e troquei o argumento state no corpo da closure com o nome do argumento abreviado $0. A instrução resultante é mais concisa, sem comprometer a legibilidade.

Trailing closures

A linguagem de programação Swift também define um conceito conhecido como trailing closures. A ideia é simples. Se você passar uma closure como o último argumento de uma função, você pode colocar essa closure fora dos parênteses da chamada de função. O exemplo a seguir demonstra como isso funciona.

Se o único argumento da chamada de função é a closure, é possível omitir os parênteses da chamada de função.

Note que isto também funciona para closures que contêm várias instruções. Na verdade, é a principal razão da trailing closure está disponível em Swift. Se uma closure for longa ou complexa, e é o último argumento de uma função, muitas vezes é melhor usar a sintaxe de training closure.

4. Capturando valores

Quando usamos closures, você encontra-se frequentemente usando ou manipulando constantes e variáveis do ambiente da closure no corpo da closure. Isso é possível e muitas vezes referido como captura de valor. Isso simplesmente significa que uma closure pode capturar os valores de constantes e variáveis do contexto que é definido. Veja o exemplo a seguir para entender melhor o conceito de captura de valor.

Tenho certeza que você concorda que o exemplo acima é um pouco amplo, mas mostra claramente como a captura de valor funciona em Swift. As funções encadeadas, changeToUppercase e changeToLowercase, tem acesso aos argumentos da função externa, changeCase, bem como a variável newString declarado na função exterior. Deixe-me explicar o que acontece.

A função changeCase aceita um boolean como primeiro argumento e o parâmetros variável do tipo String como segundo parâmetro. O parâmetro de retorno é um array de string composto pelas strings passadas para a função como segundo argumento. No corpo da função, criamos um array mutável de strings, newStrings, no qual armazenamos e manipulamos as strings.

As funções encadeadas percorrem as string que são passadas para a função changeCase e alteram o case de cada string. Como você pode ver, elas tem acesso direto as strings passadas para a função changeCase bem como o array newStrings, que é declarado no corpo da função changeCase.

Verificamos o valor de uppercase, chamando a função apropriada e retornando o array newStrings. As duas linhas no final do exemplo demonstram como funciona a função changeCase.

Mesmo que demonstrei a captura de valor com funções, lembre-se que cada função é uma closure. Em outras palavras, as mesmas regras se aplicam para closures sem nome.

Closures

Foi mencionado várias vezes neste artigo, funções são closures. Existem três tipos de closures:

  • funções globais
  • funções encadeadas
  • expressões de closures

Funções globais, tais como a função println da biblioteca padrão do Swift, sem captura de valores. Funções encadeadas, no entanto, tem acesso e podem capturar os valores das constantes e valores da função em que eles são definidos. O exemplo anterior ilustra este conceito.

Expressões de closures, também conhecido como closures anônimas, podem capturar os valores das constantes e variáveis do contexto que eles são definidos. Isto é muito semelhante a funções encadeadas.

Copiar e referênciar

Uma closure que captura o valor de uma variável é capaz de alterar o valor dessa variável. O Swift é inteligente o bastante para saber se deve copiar ou referenciar os valores das constantes e variáveis capturadas.

Os desenvolvedores que são novos em Swift e tem pouca experiência com outras linguagens de programação terá esse comportamento garantido. No entanto, é uma vantagem importante que o Swift compreenda os valores capturados como estão sendo usados em uma closure e, em conseqüência, pode lidar com gerenciamento de memória para nós.

Aprenda mais em nosso Curso de Programação de Swift

Se você está interessado em elevar sua educação em Swift para o próximo nível, você pode dar uma olhada no nosso curso completo de desenvolvimento em Swift.

Conclusão

Closures é um conceito importante e você o usará frequentemente em Swift. Eles permitem a você escrever um código dinâmico e flexível, que é fácil de escrever e entender. No próximo artigo, iremos explorar orientação a objetos em Swift, começando com objetos, estruturas e classes.

Seja o primeiro a saber sobre novas traduções–siga @tutsplus_pt no Twitter!

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.