Swift: Valores de Retorno e Tipos de Função do Swift

As funções podem retornar mais do que tipos básicos — podem retornar múltiplos valores e até retornar outras funções. Esta lição explora todo o espectro de valores de retorno de funções Swift e o conceito central de funções como cidadãs de primeira classe.

1. O Que Você Vai Aprender


2. Uma História Real de um Desenvolvedor de E-Commerce

(1) Problema: Escrever uma nova função para cada nível de desconto

Charlie está construindo um motor de promoções. Diferentes níveis de usuário recebem descontos diferentes:

SWIFT
func vipDiscount(_ price: Double) -> Double {
    return price * 0.8
}
func memberDiscount(_ price: Double) -> Double {
    return price * 0.9
}
func normalDiscount(_ price: Double) -> Double {
    return price
}

Toda vez que um novo tipo de desconto é adicionado, ele escreve outra função. Quando as regras de promoção mudam, uma pilha de código precisa ser atualizada. A troca de estratégia depende de if-else escrito à mão; não há como configurá-la dinamicamente.

(2) A Solução com Funções como Tipos

No Swift, funções são "cidadãs de primeira classe" — você pode passá-las e armazená-las como Int ou String:

SWIFT
// Define a discount strategy type
typealias DiscountStrategy = (Double) -> Double
// Use a function dictionary instead of if-else
let strategies: [String: DiscountStrategy] = [
    "vip": { $0 * 0.8 },
    "member": { $0 * 0.9 },
    "normal": { $0 }
]
// Switch strategy in one line
func applyDiscount(_ price: Double, level: String) -> Double {
    return strategies[level]?(price) ?? price
}

(3) Resultado: Estratégias configuráveis, código extensível

Dimensão Antes Depois
Adicionar um desconto Escrever função + modificar if-else Adicionar uma entrada no dicionário
Troca de estratégia if-else fixo no código Seleção dinâmica por chave
Reutilização Cada estratégia isolada, não combinável Funções combináveis e passáveis
Cobertura de testes Um teste por estratégia Framework de teste unificado

3. Múltiplos Valores de Retorno e Sobrecarga de Funções

(1) Retornando Múltiplos Valores com Tuplas

As tuplas do Swift permitem que uma função retorne vários valores de uma vez:

100%
graph LR
    A[Função retorna tupla] --> B[Elemento 1]
    A --> C[Elemento 2]
    A --> D[Elemento 3]
    B --> E["Acesso nomeado: resultado.nome"]
    C --> F["Acesso nomeado: resultado.idade"]
    D --> G["Acesso indexado: resultado.0"]
Abordagem Sintaxe Quando Usar
Tupla anônima -> (Int, String) Agrupamento simples, nomes não importantes
Tupla nomeada -> (soma: Int, media: Double) Acesso semântico aos campos necessário
Tupla optional -> (Int, String)? Função pode falhar e retornar nil

▶ Exemplo: Análise Estatística de Array

SWIFT
// ============================================
// Return multiple statistics using a named tuple
// ============================================
func analyze(_ numbers: [Int]) -> (count: Int, sum: Int, average: Double) {
    let count = numbers.count
    let sum = numbers.reduce(0, +)
    let average = count > 0 ? Double(sum) / Double(count) : 0
    return (count, sum, average)
}
let result = analyze([85, 90, 78, 92, 88])
print("Count: \(result.count)")
print("Sum: \(result.sum)")
print("Average: \(result.average)")

Saída:

TEXT 📖 Somente leitura
Count: 5
Sum: 433
Average: 86.6

(2) Sobrecarga de Funções

O Swift suporta múltiplas funções com o mesmo nome, desde que os tipos ou quantidades de parâmetros sejam diferentes:

SWIFT
func area(width: Double, height: Double) -> Double {
    return width * height
}
func area(radius: Double) -> Double {
    return Double.pi * radius * radius
}
print("Rectangle area: \(area(width: 10, height: 5))")
print("Circle area: \(area(radius: 3))")

Saída:

TEXT 📖 Somente leitura
Rectangle area: 50.0
Circle area: 28.274333882308138

4. Funções como Tipos

(1) Sintaxe de Tipo de Função

Cada função tem um tipo específico, determinado pelos tipos de seus parâmetros e tipo de retorno:

Assinatura da Função Tipo da Função
func somar(a: Int, b: Int) -> Int (Int, Int) -> Int
func log() -> Void () -> Void ou () -> ()
func saudar(_ nome: String) (String) -> Void
func dobrar(_ n: Int) -> Int (Int) -> Int
💡 Nota: Um tipo de função inclui apenas os tipos dos parâmetros e o tipo de retorno — não inclui os rótulos de argumento.

▶ Exemplo: Funções como Variáveis e Parâmetros

SWIFT
// ============================================
// Functions passed as variables and parameters
// ============================================
// 1. Define two simple functions
func add(_ a: Int, _ b: Int) -> Int { return a + b }
func multiply(_ a: Int, _ b: Int) -> Int { return a * b }
// 2. Function type variable
var operation: (Int, Int) -> Int = add
print("add: \(operation(3, 4))")
// 3. Swap the function
operation = multiply
print("multiply: \(operation(3, 4))")
// 4. Function as a parameter
func execute(_ a: Int, _ b: Int, using op: (Int, Int) -> Int) -> Int {
    return op(a, b)
}
print("execute add: \(execute(5, 6, using: add))")
print("execute multiply: \(execute(5, 6, using: multiply))")

Saída:

TEXT 📖 Somente leitura
add: 7
multiply: 12
execute add: 11
execute multiply: 30

(2) typealias para Nomeação de Tipo de Função

Quando um tipo de função é complexo ou usado em muitos lugares, dê um nome a ele com typealias:

SWIFT
// Define a function type alias
typealias IntOperation = (Int, Int) -> Int
// Use the alias for variables and parameters
func calculate(_ a: Int, _ b: Int, using op: IntOperation) -> Int {
    return op(a, b)
}
let op: IntOperation = { $0 * $0 + $1 * $1 }
print("Result: \(calculate(3, 4, using: op))")

Saída:

TEXT 📖 Somente leitura
Result: 25

5. Funções Aninhadas e Funções que Retornam Funções

(1) Funções Aninhadas

Você pode definir funções dentro de outras funções. As funções internas são acessíveis apenas dentro do escopo da função externa:

SWIFT
// ============================================
// Nested functions: define helper functions inside
// ============================================
func formatFullName(first: String, last: String) -> String {
    // Nested helper
    func capitalize(_ text: String) -> String {
        return text.prefix(1).uppercased() + text.dropFirst().lowercased()
    }
    return "\(capitalize(first)) \(capitalize(last.uppercased()))"
}
print(formatFullName(first: "alice", last: "JOHNSON"))

Saída:

TEXT 📖 Somente leitura
Alice Johnson

(2) Funções que Retornam Funções

Outra forma de funções de ordem superior — retornar uma função:

SWIFT
// ============================================
// Function factory: generate different strategy functions by parameter
// ============================================
func makeMultiplier(factor: Double) -> (Double) -> Double {
    func multiplier(_ value: Double) -> Double {
        return value * factor
    }
    return multiplier
}
let double = makeMultiplier(factor: 2)
let triple = makeMultiplier(factor: 3)
print("double(5) = \(double(5))")
print("triple(5) = \(triple(5))")

Saída:

TEXT 📖 Somente leitura
double(5) = 10.0
triple(5) = 15.0

▶ Exemplo: Fábrica de Estratégia de Desconto

SWIFT
// ============================================
// Discount factory with nested functions and function return values
// ============================================
typealias DiscountRule = (Double) -> Double
func discountFor(level: String) -> DiscountRule? {
    // Nested discount functions
    func vip(_ price: Double) -> Double { return price * 0.8 }
    func member(_ price: Double) -> Double { return price * 0.9 }
    func normal(_ price: Double) -> Double { return price }
    switch level {
    case "vip": return vip
    case "member": return member
    case "normal": return normal
    default: return nil
    }
}
if let rule = discountFor(level: "vip") {
    print("VIP discount price: $\(rule(100))")
}

Saída:

TEXT 📖 Somente leitura
VIP discount price: $80.0

6. Exemplo Completo: Motor de Promoções

SWIFT
// ============================================
// Full example: Promotions engine
// Combines: multiple returns + function types + typealias + nested functions
// ============================================
import Foundation
// 1. Define function type aliases
typealias Discount = (Double) -> Double
typealias DiscountResult = (original: Double, final: Double, saved: Double)
// 2. Discount factory — returns a nested function
func createDiscount(minSpend: Double, rate: Double) -> Discount {
    func discount(_ price: Double) -> Double {
        return price >= minSpend ? price * (1 - rate) : price
    }
    return discount
}
// 3. Multiple return values — return discount result details
func applyDiscount(price: Double, rule: Discount) -> DiscountResult {
    let final = rule(price)
    let saved = price - final
    return (price, final, saved)
}
// 4. Function as parameter — batch process orders
func processOrders(_ prices: [Double], using rule: Discount) -> [DiscountResult] {
    return prices.map { applyDiscount(price: $0, rule: rule) }
}
// 5. Use the promotions engine
let memberRule = createDiscount(minSpend: 50, rate: 0.15)
let orderResults = processOrders([120, 45, 200], using: memberRule)
for result in orderResults {
    print("$\(result.original) → $\(result.final) (saved $\(result.saved))")
}

Saída:

TEXT 📖 Somente leitura
$120.0 → $102.0 (saved $18.0)
$45.0 → $45.0 (saved $0.0)
$200.0 → $170.0 (saved $30.0)

❓ Perguntas Frequentes

P: Por que os tipos de função ignoram os rótulos de argumento? R: Os tipos de função se concentram na correspondência de tipo — os tipos dos parâmetros e o valor de retorno. Os rótulos fazem parte da convenção de chamada externa e não afetam a compatibilidade de tipo. Assim, (a: Int) -> Void e (b: Int) -> Void são o mesmo tipo. P: Qual é a diferença entre funções aninhadas e closures? R: Funções aninhadas são funções internas nomeadas. Closures são tipicamente blocos de código anônimos. Funções aninhadas podem capturar variáveis externas e se comportam de forma semelhante às closures, mas têm um nome e podem ser chamadas repetidamente. P: O typealias pode ser usado com tipos de função genéricos complexos? R: Sim. Por exemplo, typealias Transformador<T> = (T) -> T define um alias de tipo de função genérico. No entanto, no Swift, typealias não pode expressar diretamente restrições genéricas — outros mecanismos são necessários para isso. P: É melhor retornar uma tupla ou uma struct personalizada? R: Use tuplas para combinações simples (ex.: retornar dois Ints). Use structs para cenários semanticamente complexos (campos nomeados com documentação). Tuplas são adequadas para agrupamentos ad-hoc; structs são adequadas para APIs públicas. P: A sobrecarga de funções prejudica o desempenho em tempo de execução? R: Não. A resolução de sobrecarga acontece em tempo de compilação (despacho estático), sem sobrecarga em tempo de execução. O compilador Swift seleciona a versão correta com base nos tipos e na quantidade de parâmetros durante a compilação.


📖 Resumo


📝 Exercícios

  1. Iniciante: Escreva uma função dividir(_:_:) que retorna tanto o quociente quanto o resto via tupla. Chame e imprima o resultado de dividir(17, 5).
  2. Intermediário: Escreva uma função transformar para arrays [Int] que recebe um parâmetro do tipo (Int) -> Int e retorna um novo array. Depois defina um typealias para esse tipo de função.
  3. Desafio: Implemente uma "cadeia de operações" — escreva uma função encadear(_:_:) que recebe um valor Int inicial e um array de funções [(Int) -> Int], aplica cada função ao valor em sequência e retorna o resultado final. Crie três funções de transformação e componha uma cadeia.
Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%