Se retirares todos os nomes e etiquetas de uma assinatura de função em Swift, ficas apenas com o tipo da função.
func shoppingList(item: String, quantity: Int) -> String {
"You need to buy \(quantity) \(item)."
}
// shoppingList: (String, Int) -> String
func repeater(_ phrase: String, times: Int) -> String {
var result = ""
for _ in 1...times {
result += phrase
}
return result
}
// repeater: (String, Int) -> String
func printString(line: String) {
print(line)
}
// printString: (String) -> ()
Repara que os tipos das duas primeiras funções são iguais, (String, Int) -> String, ainda que as assinaturas sejam diferentes e as duas funções façam coisas muito diferentes. Ambas recebem uma String e um Int como parâmetros de entrada e devolvem uma String. E, como se vê pelo tipo da terceira função, embora o corpo da função não pareça devolver nada, na verdade devolve implicitamente (), o único valor do tipo Void.
Estes tipos de função podem ser usados da mesma forma que qualquer outro tipo em Swift; por exemplo, podem ser usados na declaração de variáveis ou constantes. E, como em Swift as funções são valores, podes atribuir funções já existentes a essas constantes ou variáveis:
var stringAndIntToString: (String, Int) -> String
stringAndIntToString = shoppingList
stringAndIntToString("carrots", 3)
// => "You need to buy 3 carrots."
Tal como acontece com outras variáveis ou constantes, o valor que lhe atribuis tem de ser do tipo correto:
stringAndIntToString = printShoppingList
// Error: Cannot assign value of type '(String) -> ()' to type '(String, Int) -> String'
Como os tipos de função podem ser usados em qualquer sítio onde se usem outros tipos, também podem ser usados como tipos de parâmetros, passados para outras funções e chamados a partir do interior dessas funções.
func apply3(to str: String, function f: (String, Int) -> String) -> String {
f(str,3)
}
// apply3: ([String], (String, Int) -> String) -> [String]
apply3(to: "eggs", function: shoppingList)
// => "You need to buy 3 eggs."
apply3(to: "eggs", function: repeater)
// => "eggseggseggs"
Da mesma forma, os tipos de função podem ser usados como tipos devolvidos por funções. Por outras palavras, podes escrever funções que criam e devolvem outras funções. Ao criar estas funções, a função devolvida pode usar os outros parâmetros passados para a função ou as variáveis locais criadas dentro da função principal.
func makeAdder(base: Int) -> (Int) -> Int {
func adder(_ i: Int) -> Int {
base + i
}
return adder
}
// makeAdder: (Int) -> (Int) -> Int
let add10 = makeAdder(base: 10)
// add10: (Int) -> Int
let subtract20 = makeAdder(base: -20)
// subtract10: (Int) -> Int
add10(5)
// => 15
subtract20(5)
// => -15
Olá, Agente Double-Null0111.
A tua missão, se decidires aceitá-la, é escrever um par de ferramentas que te ajudem a infiltrar-te no quartel-general da UMBRA (Lacaios Unidos Realmente Horríveis) e a recuperar os planos do seu mais recente esquema verdadeiramente horrível. Vais precisar de duas ferramentas para levar a cabo esta missão.
Depois de teres os planos secretos, vais precisar de os proteger para que só quem souber a palavra-passe os possa recuperar.
Para isso, vais precisar de implementar a função protectSecret(_ secret: String, withPassword password: String) -> (String) -> String.
Esta função devolve outra função que recebe possíveis palavras-passe como parâmetros de entrada.
Se a palavra-passe introduzida estiver correta, a nova função devolve o segredo escondido; mas se a palavra-passe estiver errada, a função devolve "Sorry. No hidden secrets here."
let secretFunction = protectSecret("Steal the world's supply of french fries!", withPassword: "5up3r53cr37")
secretFunction("Open sesame")
// Returns "Sorry. No hidden secrets here."
secretFunction("5up3r53cr37")
// Returns "Steal the world's supply of french fries!"
Descobrimos que a UMBRA baseia todas as combinações dos seus cofres no número da sala onde se encontram. As combinações dos cofres são geradas aplicando repetidamente uma função especial ao número da sala. Assim, o primeiro número da combinação vem de aplicar a função ao número da sala, o segundo vem de aplicar a função ao primeiro número e o terceiro vem de aplicar a função ao segundo número.
No entanto, a UMBRA muda regularmente a função usada para gerar as combinações, por isso a tua ferramenta vai precisar de receber tanto um número de sala como a função adequada para gerar a combinação.
Implementa a função generateCombination(forRoom room: Int, usingFunction f: (Int) -> Int) -> (Int, Int, Int) para gerar a combinação de que vais precisar.
func makeCombo(_ x: Int) -> Int {
(x * 13) % 256
}
generateCombination(forRoom: 227, usingFunction: makeCombo)
// Returns (135, 219, 31)
Inscreve-te no Exercism para aprenderes e dominares Swift com 35 conceitos116 exercícios, e mentoria humana real, tudo grátis.