Closures em Swift são blocos de código autocontidos que podem receber parâmetros para acionar seu cálculo e retornar valores Closures também capturam valores de seu ambiente e os usam em seus cálculos. Como são autocontidos, podem ser passados de um lado para o outro em um programa como outros valores ou atribuídos a constantes e variáveis.
Closures podem soar muito parecidos com funções em Swift; e de fato são, por um bom motivo. Funções em Swift são casos especiais de closures que precisam ter um nome e são definidas com uma sintaxe um pouco diferente.
Embora funções em Swift sejam tecnicamente closures, quando as pessoas falam de "closures" em Swift, estão falando de expressões de closure.
Expressões de closure são escritas como uma lista de parâmetros seguida de um tipo de retorno e da palavra-chave in, seguida do corpo do closure, tudo dentro de um par de chaves:
{ (a: Double, b: Double) -> Double in
return (a + b) / 2.0
}
Isso define uma expressão de closure do tipo (Double, Double) -> Double, e ela pode ser executada de maneira semelhante a uma função desse tipo, aplicando-a a parâmetros do tipo adequado:
{ (a: Double, b: Double) -> Double in
return (a + b) / 2.0
}(10.0, 15.0)
// returns 12.5
Como não é muito conveniente escrever a expressão de closure completa toda vez que se quer executá-la, closures podem ser atribuídos a nomes, como qualquer outro valor em Swift. Eles podem então ser chamados aplicando o nome aos parâmetros:
let mean = { (a: Double, b: Double) -> Double in
(a + b) / 2.0
}
mean(13.0, 100.0)
// returns 56.5
Como visto acima, closures, assim como funções comuns, podem omitir a palavra-chave return se o corpo do closure for uma única expressão.
Na maioria das vezes, closures são usados com funções de ordem superior, seja passados como parâmetros ou retornados como resultados:
[11, 75, 3, 99, 53].contains(where: { (x: Int) -> Bool in x > 100 })
// returns false
["apple", "ball", "carrot"].sorted(by: { (s1: String, s2: String) -> Bool in s1.count < s2.count })
// returns ["ball", "apple", "carrot"]
func makeAdder(base: Int) -> (Int) -> Int {
{ (x: Int) -> Int in base + x }
}
Olá de novo, Agente Double-Null0111.
As forças da UMBRA estão de novo em ação, e cabe a você frustrar o mais recente plano delas. Nossa divisão de inteligência nos informa que aqueles Minions estão planejando detonar uma bomba fétida no baile do Governador.
Como os Minions são muito desastrados, muitas vezes eles armam as bombas fétidas sem querer em seus laboratórios e escritórios. E como eles vivem esquecendo como desarmar suas bombas fétidas, eles implementaram um sistema que gera as instruções de desarme, que listam a ordem em que os fios devem ser cortados a partir do número de ID da bomba.
Seu trabalho é escrever o código que vai permitir que você desarme a bomba fétida no baile antes que ela exploda.
Há três fios de cores diferentes em cada bomba fétida.
Escreva um closure que recebe uma tupla (String, String, String) e retorna a tupla com a ordem dos dois primeiros elementos invertida.
Atribua esse closure ao nome flip.
É importante notar que o tipo precisa ser o ChangeClosure (ou um sendable type), a definição do tipo está no arquivo stub.
Caso contrário, o código não vai compilar.
flip(("red", "yellow", "blue"))
// Returns ("yellow", "red", "blue")
Escreva um closure que recebe uma tupla (String, String, String) e retorna a tupla com a ordem dos fios girada para a esquerda.
Atribua esse closure ao nome rotate.
É importante notar que o tipo precisa ser o ChangeClosure (ou um sendable type), a definição do tipo está no arquivo stub.
rotate(("red", "yellow", "blue"))
// Returns ("yellow", "blue", "red")
Para descobrir a ordem em que os fios da bomba fétida devem ser cortados, você vai precisar implementar uma função que gera a função de embaralhamento adequada com base no número de ID da bomba fétida.
Implemente a função:
makeShuffle(
flipper: @escaping ((String, String, String)) -> (String, String, String),
rotator: @escaping ((String, String, String)) -> (String, String, String)
) -> ([UInt8], (String, String, String)) -> (String, String, String)
que recebe como entrada um closure que troca dois fios e um closure que gira os três fios, e retorna um closure. Esse closure retornado recebe o número de ID da bomba fétida e a ordem dos três fios, e então calcula a ordem em que os fios precisam ser cortados. O número de ID é formado por oito bits, e cada bit vai determinar se os fios devem ser trocados ou girados.
Para cada bit do número de ID, começando pelo bit mais à direita, você vai aplicar o closure flipper à tupla de fios se o bit for 0, e vai aplicar o closure rotator se for 1, obtendo o novo estado dos fios.
Depois que os closures apropriados tiverem sido aplicados para todos os oito bits do ID, o estado final dos fios é a ordem em que eles precisam ser cortados.
let shuffler = makeShuffle(flipper: flip, rotator: rotate)
// Returns ([UInt8], (String, String, String)) -> (String, String, String)
shuffler([1, 0, 0, 1, 1, 0, 1, 1], ("red", "yellow", "blue"))
// Returns ("red", "blue", "yellow")
Crie sua conta no Exercism para aprender e dominar Swift com 35 conceitos116 exercícios e mentoria humana de verdade, tudo de graça.