Portuguese (Português) translation by David Batista (you can also view the original English article)
Introdução
Currying é uma característica existente na maioria das linguagens de programação modernas. Ela traduz uma simples função com multiplos argumentos em uma série de funções, cada um com um argumento. Em essência, isto permite armazenar funções em variáveis e criar funções que retornam funções.
Apesar de isso parecer um conceito estranho no começo, é uma técnica poderosa que pode ser muito útil às vezes. Neste tutorial, eu irei mostrar para vocês como tomar vantangem do currying de função em Swift.
1. Currying de função com classes
Antes de definir nossas próprias funções personalizadas, primeiro vou te mostrar um exemplo simples de currying em Swift usando classes.
Abra o Xcode, crie um novo playground iOS ou OS x e adicione o código a seguir.
1 |
class Car { |
2 |
var speed = 0 |
3 |
|
4 |
func accelerateBy(factor: Int) -> Int { |
5 |
speed += factor |
6 |
return speed |
7 |
}
|
8 |
}
|
9 |
|
10 |
let car1 = Car() |
Nós definimos uma classe básica com uma propriedade e um método de instância ou função. Nós também criamos uma instância da classe, car1
. Nós podemos chamar o método accelerateBy(_:)
da nossa instância da Car
com o seguinte código:
1 |
car1.accelerateBy(10) |
Entretanto, há outra forma de executar este método através do uso do currying de função. No exemplo acima, você chama o método diretamente no car1
apesar do método na verdade ser definido na classe Car
. O método que escrevemos não é específico para a instância car1
, mas sim a classe de Car
. Quando você chama este método, o que realmente acontece é que o Swift primeiro vai para a classe Car
, recupera o método accelerateBy(_:)
, diz que o método da instância está sendo usado, e em seguida, executa um método alterado especifico para essa instância. Para mostrar como isso funciona, adicione a seguinte linha ao seu playground:
1 |
Car.accelerateBy(car1) |
O que estamos fazendo aqui é estar acessando o método accelerateBy(_:)
da classe Car
e passando, como um parâmetro, qual instância queremos essa função a ser executada. Na barra lateral do seu playground, você pode ver que o resultado deste método é outra função.



O que representa este resultado (Function) é na verdade um novo método de accelerateBy(_:)
específico para a instância de car1
. Está função retornada é única pelo fato de fazer regência a propriedade speed
de car1
ao invés do método genérico que você definiu anteriormente, que pode referenciar a propriedade speed
de qualquer instância Car
.
Como você pode esperar, nós podemos passar novos parâmetros para está função retornada para executa-la como fazemos normalmente. Adiciona a linha de código a seguir em seu playground.
1 |
Car.accelerateBy(car1)(10) |
Com este código, podemos passar 10
como parâmetro para o método exclusivo accelerateBy(_:)
e obter a velocidade corrente do car1
, retornada como resultado.



Parabéns! Você tirou vantagem da currying de função em Swift pela primeira vez.
Além de currying com múltiplas funções, o resultado Function que seu código está retornando também pode ser armazenado em uma variável. Isto permite que você armazene e facilmente reuse o método específico accelerateBy(_:)
para sua instância car1
. Adiciona as linhas a seguir no seu playground.
1 |
let a = Car.accelerateBy(car1) |
2 |
a(10) |
3 |
a(20) |
4 |
a(30) |
Você pode ver agora que a variável a
se comporta como qualquer outra função definida globalmente. A vantagem é que é especifica para uma instância particular de Car
, que pode ser definida em tempo de execução ao invés de tempo de compilação. Em seu playground, você pode ver os resultados esperados que está sendo exibido na barra lateral.



Mais tarde, eu irei mostrar à você como você pode retornar uma função de outra função reimplementando o comportamento da classe Car
. Nós vamos fazer isso definindo uma função que retorna outra função. No seu código, essa função ficará como abaixo:
1 |
func someFunction(input: AnyObject) -> (AnyObject) -> AnyObject { |
2 |
// Do stuff to return a function
|
3 |
}
|
Nós definimos a função someFunction(_:)
, que recebe um parâmetro AnyObject
e retorna outra função que também aceita um parâmetro AnyObject
que retorna um resultado AnyObject
. Este tipo de definição de função pode parecer muito confusa e assustadora no começo. Para simplificar isso, nós vamos tirar vantagem do palavra-chave typealias
em Swift para mapear um novo nome para qualquer tipo de dados.
Adiciona as linhas a seguir no seu playground.
1 |
typealias IntFunction = (Int) -> Int |
2 |
func accelerationForCar(car: Car) -> IntFunction { |
3 |
return Car.accelerateBy(car) |
4 |
}
|
5 |
|
6 |
let newA = accelerationForCar(car1) |
7 |
newA(10) |
Usando typealias
para mapear o nome IntFunction
para o tipo de dados (Int) -> Int
, nós temos uma definição da função accelerationForCar(_:)
muito simplificada. O tipo de dado (Int) -> Int
simplesmente representa uma função que recebe um parâmetro Int
e retorna um valor Int
.
Esta nova função utiliza o comportamento embutido da classe Car
para retornar um objeto IntFunction
que pode ser armazenado em uma variável e usada como nós fizemos anteriormente.
2. Currying de funções personalizadas
Apesar do currying de função interna ser muito útill em Swift, você poderá criar suas próprias funções que não são relacionadas a classes. Para esta parte do tutorial, nós primeiro vamos usar como exemplo uma função que multiplica outro numero por um valor constante.
Imagine que você precisa criar uma função que recebe um simples número de entrada e multiplica ele por 5. Está simples função será como mostrada abaixo:
1 |
func multiplyBy5(a: Int) -> Int { |
2 |
return a * 5 |
3 |
}
|
Agora imagine que você precisa de uma função similar, mas você precisa multiplicar por 10 ao invés de 5. Então você precisa de outra função que multiplique por 20. Apesar de você poder criar três funções similares e nomeá-las de multiplyBy5
, multiplyBy5
e multiplyBy20
, isso pode ser resolvido de uma forma mais fácil usando currying de função.
Adiciona as linhas a seguir no seu playground.
1 |
func multiplyBy(a: Int) -> IntFunction { |
2 |
func nestedMultiply(b: Int) -> Int { |
3 |
return a * b |
4 |
}
|
5 |
|
6 |
return nestedMultiply |
7 |
}
|
8 |
|
9 |
multiplyBy(10)(20) |
10 |
let multiplyBy5 = multiplyBy(5) |
11 |
multiplyBy5(4) |
Nós definimos a função multipliBy(_:)
que recebe um Int
como seu único parâmetro e retorna uma função do tipo IntFunction
, o tipo de dado que nós definimos anteriormente neste tutorial. Nesta função, nós definimos outra função, nestedMultiply(_:)
. Nós encadeamos esta função dentro da primeira para ela não poder ser executada fora do escopo da função multiplyBy(_:)
e ter acesso ao parâmetros a
de entrada.
As três linhas abaixo da definição da função são simples exemplos de como você pode utilizar essas funções em conjunto.



Embora você possa criar funções para utilizar o currying usando funções encadeadas, você também pode cria-las usando closures ou definindo vários conjuntos de parâmetros. Como um exemplo, adicione o código abaixo em seu playground.
1 |
func add(a: Int) -> IntFunction { |
2 |
return { b in a + b } |
3 |
}
|
4 |
|
5 |
let add2 = add(2) |
6 |
add2(4) |
7 |
|
8 |
func subtract(a: Int)(b: Int) -> Int { |
9 |
return b - a |
10 |
}
|
11 |
|
12 |
let subtract5 = subtract(5) |
13 |
subtract5(b: 8) |
Como você pode ver, estas duas funções podem ser usadas juntas na mesma forma que todas as outras funções têm sido ao longo deste tutorial. A unica exceção é que, com a função definida com dois conjuntos de parâmetros, você deve nomear explicitamente o segundo parâmetro.
Não há limite para o número de níveis de currying de função que você pode implementar em seu código. O código a seguir mostra um exemplo de três curried de função e como ele difere de uma única função com três parâmetros.
1 |
func multiply(a: Int, b: Int, c: Int) -> Int { |
2 |
return a * b * c |
3 |
}
|
4 |
|
5 |
func multiply(a: Int) -> (Int) -> IntFunction { |
6 |
func nestedMultiply1(b: Int) -> IntFunction { |
7 |
func nestedMultiply2(c: Int) -> Int { |
8 |
return a * b * c |
9 |
}
|
10 |
|
11 |
return nestedMultiply2 |
12 |
}
|
13 |
|
14 |
return nestedMultiply1 |
15 |
}
|
16 |
|
17 |
multiply(4, 5, 6) |
18 |
multiply(4)(5)(6) |
A principal diferença entre estas duas funções de multiplicação é que a versão curried pode efetivamente ser pausada e armazenada em uma variável após o primeiro ou segundo parâmetro ser processado. Isto torna a função muito fácil de ser reutilizada e ser passada como um objeto.
Conclusão
Currying de função é um conceito difícil de compreender, mas, em seu núcleo, ele trabalha basicamente em cima de dois conceitos chave:
- criando funções que retornam outras funções
- reduzindo funções com múltiplos argumentos em uma serie de funções, cada uma com um argumento.
Há uma variedade de maneiras de usar o curry de funções, apesar de apenas o tipo de dados Int
ser usado neste tutorial, os mesmos processos podem ser usados com qualquer tipo de dados em seus projetos de Swift. Isto possibilita que funções sejam armazenadas em variáveis e serem usadas varias vezes ao longo de seu código.
Como sempre, por favor, certifique-se de deixar seus comentários e feedback abaixo nos comentários.
Seja o primeiro a saber sobre novas traduções–siga @tutsplus_pt no Twitter!