English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Encerramento (Closure) no Swift

Neste artigo, você aprenderá o que são闭包, a sintaxe e os tipos de闭包no Swift através de exemplos.

No artigo sobre funções do Swift, usamos a palavra-chave func para criar uma função. No entanto, o Swift também possui outro tipo especial de função chamado闭包, que pode ser definido sem a palavra-chave func e o nome da função.
Como as funções, os闭包podem aceitar parâmetros e retornar valores. Eles também contêm um conjunto de instruções que são executadas após a chamada e podem ser atribuídos a variáveiscomo funções./Constantes.

Os闭包no Swift são semelhantes aos de C e Objective-C.-Os bloco de código no C e as funções anônimas em outros linguagens de programação são muito semelhantes.

As funções globais e as funções aninhadas são na verdade闭包especiais.

As formas de encerramento são:

Função globalFunção aninhadaExpressão de encerramento
Com nome, mas não pode capturar nenhum valor.Com nome, também pode capturar valores dentro da função encerrada.Encerramento sem nome, usando sintaxe leve, pode capturar valores do ambiente contextual.

Existem muitos pontos de otimização dos encerramentos no Swift:

  • Infere o tipo de parâmetro e de retorno com base no contexto

  • Retorna implicitamente da expressão de encerramento de uma linha (ou seja, o corpo do encerramento tem apenas uma linha de código e pode omitir return)

  • Pode usar nomes de parâmetros abreviados, como $0, $1(a partir de 0, representando o i-ésimo parâmetro...)

  • Fornecido com sintaxe de encerramento de cauda (Trailing closure syntax)

Sintaxe

A seguinte definição de encerramento define um parâmetro e retorna o tipo especificado:

{(parameters) -> return type in
   statements
}

Exemplo online

let simpleClosure = {
    print("Olá, Mundo!")
}
simpleClosure()

O resultado de execução do programa acima é:

Olá, Mundo!

A seguinte forma de encerramento recebe dois parâmetros e retorna um valor booleano:

{(Int, Int) -> Bool in
   Statement1
   Statement 2
    ---
   Statement n
}

Exemplo online

let simpleClosure: (String) -> (String) = { name in
    
    let greeting = "Olá, Mundo!" + "Program"
    return greeting
}
let result = simpleClosure("Olá, Mundo")
print(result)

O resultado de execução do programa acima é:

Olá, Mundo! Program

Expressão de encerramento

Expressão de encerramento é uma maneira de construir uma função anônima com sintaxe concisa. A expressão de encerramento oferece algumas otimizações de sintaxe, tornando a escrita de funções mais simples e clara.

método sorted

A biblioteca padrão do Swift fornece uma chamada chamada sorted(by:) O método, com base na função de encerramento fornecida para a ordenação, ordenará os valores do array de tipo conhecido.

Após a ordenação, o método sorted(by:) retornará um novo array do mesmo tamanho que o array original, contendo elementos do mesmo tipo e ordenados corretamente. O array original não será modificado pelo método sorted(by:)

O método sorted(by:) precisa passar dois parâmetros:

  • Array de tipo conhecido

  • Função de encerramento, essa função de encerramento precisa passar dois valores do mesmo tipo que os elementos do array e retornar um valor booleano para indicar se, após a ordenação, o primeiro parâmetro inserido está antes ou depois do segundo parâmetro. Se o valor do primeiro parâmetro aparecer antes do valor do segundo parâmetro, a função de encerramento de ordenação precisa retornar true, ao contrário, retorna false.

Exemplo online

import Cocoa
let names = ["AT", "AE", "D", "S", "BE"]
// Usar função comum (ou função aninhada) para fornecer função de classificação, o tipo da função do encerramento deve ser (String, String) -> Bool.
func backwards(s1: String, s2: String) -> Bool {
    return s1 > s2
}
var reversed = names.sorted(by: backwards)
print(reversed)

O resultado de execução do programa acima é:

["S", "D", "BE", "AT", "AE"]

se a primeira string (s1), é maior que a segunda string (s2), a função backwards retorna true, indicando que s1deve aparecer em s2antes. Para os caracteres de uma string, "maior" significa "aparecer mais tarde em ordem alfabética". Isso significa que a letra "B" é maior que a letra "A", a string "S" é maior que a string "D". Isso fará a ordenação inversa das letras, "AT" ficará antes de "AE".

abreviação de nomes de parâmetros

O Swift fornece automaticamente a funcionalidade de abreviação de nomes de parâmetros para funções aninhadas, você pode passar diretamente $0, $1,2para chamar os parâmetros do encerramento em ordem.

Exemplo online

import Cocoa
let names = ["AT", "AE", "D", "S", "BE"]
var reversed = names.sorted(by: { $0 > $1 })
print(reversed)

$0 e $1representa os primeiros e segundos parâmetros do tipo String.

O resultado de execução do programa acima é:

["S", "D", "BE", "AT", "AE"]

Se você usar abreviações de nomes de parâmetros em uma expressão de encerramento, você pode omitir a definição deles na lista de parâmetros do encerramento e o tipo das abreviações de nomes dos parâmetros será inferido pelo tipo da função. A palavra-chave in também pode ser omitida.

função operador

Na verdade, há uma maneira ainda mais curta de escrever a expressão de encerramento no exemplo acima.

do SwiftStringO tipo define informações sobre o sinal de maior (>) implementação de string, que como uma função aceita doisStringparâmetros e retornaBoolvalores do tipo. E isso coincide comsort(_)O segundo parâmetro do método precisa ser do tipo de função correspondente. Portanto, você pode simplesmente passar um sinal de maior, o Swift pode inferir automaticamente que você deseja usar a implementação de função de string com sinal de maior:

import Cocoa
let names = ["AT", "AE", "D", "S", "BE"]
var reversed = names.sorted(by: >)
print(reversed)

O resultado de execução do programa acima é:

["S", "D", "BE", "AT", "AE"]

Encerramento de cauda

Um encerramento subsequente é uma expressão de encerramento escrita após os parênteses de uma função, que suporta chamá-lo como o último parâmetro.

func someFunctionThatTakesAClosure(closure: () -> Void) {
    // parte do corpo da função
}
// Aqui está a chamada de função sem usar encerramento subsequente
someFunctionThatTakesAClosure({
    // Parte principal do encerramento
)
// Aqui está a chamada de função usando encerramento subsequente
someFunctionThatTakesAClosure() {}}
  // Parte principal do encerramento
}

Exemplo online

import Cocoa
let names = ["AT", "AE", "D", "S", "BE"]
//Encerramento de cauda
var reversed = names.sorted() { $0 > $1 }
print(reversed)

Depois de sort() { $0 > $1} como encerramento de cauda.

O resultado de execução do programa acima é:

["S", "D", "BE", "AT", "AE"]

Atenção: Se a função precisar apenas de um parâmetro de expressão de encerramento, quando você usar o encerramento de cauda, você pode até omitir()Omitido.

reversed = names.sorted { $0 > $1 }

Valores capturados

O encerramento pode capturar constantes ou variáveis no contexto de sua definição.

Mesmo que o domínio original dos valores das constantes e variáveis já não exista, o encerramento ainda pode referenciar e modificar esses valores dentro do corpo do encerramento.

A forma mais simples de encerramento no Swift é a função aninhada, que é uma função definida dentro do corpo de outra função.

As funções aninhadas podem capturar todos os parâmetros e constantes ou variáveis definidas nas funções externas.

Veja este exemplo:

func makeIncrementor(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementor() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementor
}

Uma função makeIncrementor, que tem um parâmetro do tipo Int chamado amout, e um parâmetro externo chamado forIncremet, o que significa que você deve usar esse nome externo ao chamá-la. O valor de retorno é um()-> Intda função.

No corpo da função, foram declaradas as variáveis runningTotal e uma função incrementor.

A função incrementor não recebe nenhum parâmetro, mas acessa as variáveis runningTotal e amount dentro do corpo da função. Isso é porque ele realiza isso capturando as variáveis runningTotal e amount que já existem no corpo da função que a contém.

Como não foi modificado o valor da variável amount, o incrementor realmente captura e armazena uma cópia dessa variável, e essa cópia é armazenada junto com o incrementor.

Portanto, quando chamamos essa função, acumulamos:

import Cocoa
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementor() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementor
}
let incrementByTen = makeIncrementor(forIncrement: 10)
// O valor retornado é10
print(incrementByTen())
// O valor retornado é20
print(incrementByTen())
// O valor retornado é30
print(incrementByTen())

O resultado de execução do programa acima é:

10
20
30

O encerramento é um tipo de referência

No exemplo acima, incrementByTen é uma constante, mas esses encerramentos apontados ainda podem aumentar o valor das variáveis capturadas.

Isso porque a função e o encerramento são tipos de referência.

Independentemente de você passar a função/Seja você atribua o encerramento a uma constante ou a uma variável, na verdade você está atribuindo uma constante/O valor da variável é configurado para a função correspondente/Referência de encerramento. No exemplo acima, incrementByTen aponta para a referência do encerramento é uma constante, e não o conteúdo do encerramento em si.

Isso também significa que se você atribuir um encerramento a duas constantes diferentes/Variáveis, ambos os valores apontam para o mesmo encerramento:

import Cocoa
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementor() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementor
}
let incrementByTen = makeIncrementor(forIncrement: 10)
// O valor retornado é10
incrementByTen()
// O valor retornado é20
incrementByTen()
// O valor retornado é30
incrementByTen()
// O valor retornado é40
incrementByTen()
let alsoIncrementByTen = incrementByTen
// O valor retornado também é50
print(alsoIncrementByTen())

O resultado de execução do programa acima é:

50