Swift: Definição de Funções e Parâmetros do Swift
As funções são os blocos fundamentais de construção de código no Swift. Esta lição ensina como definir funções e usar cada forma de parâmetro com flexibilidade, tornando seu código mais semântico e reutilizável.
1. O Que Você Vai Aprender
- Definir e chamar funções usando a palavra-chave
func - Entender a diferença entre rótulos de argumento e nomes de parâmetro
- Definir valores padrão para parâmetros
- Usar
inoutpara mutação de parâmetro no local - Lidar com um número variável de argumentos com parâmetros variádicos
2. Uma História Real de um Engenheiro Back-End
(1) Problema: Significado pouco claro dos parâmetros no local da chamada
Bob está desenvolvendo um sistema de pedidos de e-commerce. Ele escreveu uma função para calcular o preço total do pedido:
func calculate(price: Double, count: Int, rate: Double) -> Double {
return price * Double(count) * (1 - rate)
}
// At the call site — parameter meaning is guesswork
let result = calculate(price: 100, count: 3, rate: 0.1)
A equipe se dividiu sobre o que taxa: 0.1 significava — alguns achavam que era um imposto de 10%, outros achavam que era um desconto de 10%. A assinatura da função não expressava o papel semântico de cada parâmetro.
(2) A Solução com Rótulos de Argumento
O Swift permite definir tanto um rótulo externo quanto um nome interno para cada parâmetro, fazendo o local da chamada parecer linguagem natural:
func calculate(price: Double, count: Int, discount rate: Double) -> Double {
return price * Double(count) * (1 - rate)
}
// Call site is clear: "discount" tells you it's a discount rate
let result = calculate(price: 100, count: 3, discount: 0.1)
(3) Resultado: Chamadas de função semanticamente claras
| Dimensão | Antes | Depois |
|---|---|---|
| Significado do parâmetro | Pura adivinhação | Compreensível no local da chamada |
| Legibilidade do código | Precisa pular para a definição | Significado claro em uma linha |
| Comunicação da equipe | Debates frequentes sobre significado | Assinatura da função autodocumentada |
| Eficiência de manutenção | Busca global ao alterar parâmetros | Mudanças locais, sem ambiguidade |
3. Definição Básica de Função
Uma função é um bloco de código reutilizável no Swift, definido com a palavra-chave func.
graph LR
A[palavra-chave func] --> B[Nome da função]
B --> C[Lista de parâmetros]
C --> D[Seta de retorno e tipo]
D --> E[Corpo da função]
A --> F["func saudacao(nome: String) -> String { return \"Olá \\(nome)\" }"]
| Componente | Obrigatório | Observações |
|---|---|---|
Palavra-chave func |
Sim | Marca uma declaração de função |
| Nome da função | Sim | Identifica a função, use camelCase |
Lista de parâmetros () |
Sim | Parênteses vazios mesmo sem parâmetros |
Retorno -> Tipo |
Não | Omita para retornar Void |
Corpo {} |
Sim | O bloco de código executado pela função |
(1) Sem Parâmetros, Sem Valor de Retorno
func sayHello() {
print("Hello!")
}
sayHello() // Call
Saída:
TEXT 📖 Somente leituraHello!
(2) Parâmetros e Valores de Retorno
func add(a: Int, b: Int) -> Int {
return a + b
}
let sum = add(a: 5, b: 3)
print("5 + 3 = \(sum)")
Saída:
TEXT 📖 Somente leitura5 + 3 = 8
▶ Exemplo: Cálculo do Valor do Pedido
// ============================================
// Calculate order total including tax
// ============================================
func orderAmount(price: Double, quantity: Int) -> Double {
return price * Double(quantity)
}
let amount = orderAmount(price: 29.99, quantity: 3)
print("Order amount: $\(amount)")
Saída:
TEXT 📖 Somente leituraOrder amount: $89.97
4. Rótulos de Argumento e Valores Padrão
(1) Rótulos de Argumento
O Swift permite especificar um rótulo externo (usado no local da chamada) e um nome interno (usado dentro do corpo da função) para cada parâmetro:
| Estilo | Sintaxe | Local da Chamada | Quando Usar |
|---|---|---|---|
| Rótulo = nome | func foo(nome: String) |
foo(nome: ...) |
O nome do parâmetro é suficientemente semântico |
| Rótulo externo | func foo(com nome: String) |
foo(com: ...) |
A chamada parece linguagem natural |
| Omitir rótulo | func foo(_ nome: String) |
foo(...) |
O verbo já expressa o parâmetro |
| Combinações | Rótulos variados | Flexível | Requisitos personalizados |
▶ Exemplo: Comparando Estilos de Rótulo
// ============================================
// Three argument label styles compared
// ============================================
// 1. Default — label equals name
func greet1(name: String) {
print("Hello, \(name)")
}
// 2. Custom external label
func greet2(to name: String) {
print("Hello, \(name)")
}
// 3. Omit external label (underscore)
func greet3(_ name: String) {
print("Hello, \(name)")
}
greet1(name: "Alice")
greet2(to: "Bob")
greet3("Charlie")
Saída:
TEXT 📖 Somente leituraHello, Alice Hello, Bob Hello, Charlie
(2) Valores Padrão de Parâmetro
Quando você fornece um valor padrão para um parâmetro, os chamadores podem omitir esse argumento:
func makeCoffee(size: String, sugar: Int = 1) -> String {
return "\(size) coffee with \(sugar) sugar(s)"
}
print(makeCoffee(size: "Large")) // Uses default sugar
print(makeCoffee(size: "Medium", sugar: 0)) // Custom sugar
Saída:
TEXT 📖 Somente leituraLarge coffee with 1 sugar(s) Medium coffee with 0 sugar(s)💡 Dica: Coloque os parâmetros padrão no final da lista de parâmetros para evitar ambiguidade nos locais de chamada.
5. Parâmetros Variádicos e inout
(1) Parâmetros Variádicos
Um parâmetro variádico aceita zero ou mais valores de um determinado tipo e fica disponível como um array dentro do corpo da função:
func sum(_ numbers: Double...) -> Double {
var total = 0.0
for number in numbers {
total += number
}
return total
}
print(sum(1, 2, 3)) // 3 arguments
print(sum(10, 20)) // 2 arguments
print(sum()) // 0 arguments
Saída:
TEXT 📖 Somente leitura6.0 30.0 0.0
| Característica | Descrição |
|---|---|
| Sintaxe | Adicione ... após o tipo |
| Quantidade | 0 a qualquer número |
| Tipo | Todos os valores devem ser do mesmo tipo |
| Posição | No máximo um por função; deve ser o último parâmetro |
(2) Parâmetros inout
Um parâmetro inout permite que uma função modifique a variável do chamador — essencialmente passagem por referência em vez de por cópia:
// ============================================
// inout parameter: swapping two variables
// ============================================
func swapValues(_ a: inout Int, _ b: inout Int) {
let temp = a
a = b
b = temp
}
var x = 10
var y = 20
swapValues(&x, &y)
print("x = \(x), y = \(y)")
Saída:
TEXT 📖 Somente leiturax = 20, y = 10⚠️ Nota: Prefixe a variável com
&ao passar para um parâmetroinout. Você não pode passar constantes ou literais.
▶ Exemplo: Calculadora Universal de Média
// ============================================
// Variadic + inout combined: compute average and track calls
// ============================================
func average(_ scores: Double..., record callCount: inout Int) -> Double {
callCount += 1
guard !scores.isEmpty else { return 0 }
var total = 0.0
for score in scores {
total += score
}
return total / Double(scores.count)
}
var callTimes = 0
print("Average: \(average(85, 90, 78, record: &callTimes))")
print("Average: \(average(100, 95, record: &callTimes))")
print("Function called \(callTimes) times")
Saída:
TEXT 📖 Somente leituraAverage: 84.33333333333333 Average: 97.5 Function called 2 times
6. Exemplo Completo: Calculadora de Desconto de Pedido
// ============================================
// Full example: Order discount calculator
// Combines argument labels, defaults, variadic, inout
// ============================================
import Foundation
// 1. Compute subtotal (variadic)
func subtotal(_ prices: Double...) -> Double {
var total = 0.0
for price in prices {
total += price
}
return total
}
// 2. Apply discount (default parameter + argument label)
func applyDiscount(to total: Double, rate: Double = 0.1) -> Double {
return total * (1 - rate)
}
// 3. Log orders (inout parameter)
func logOrder(_ description: String, counter: inout Int) {
counter += 1
print("[\(counter)] \(description)")
}
// 4. Simulate order processing
var orderCount = 0
let item1 = subtotal(29.99, 49.99)
let item2 = subtotal(9.99, 14.99, 24.99)
logOrder("Item 1 subtotal: $\(item1)", counter: &orderCount)
logOrder("Item 2 subtotal: $\(item2)", counter: &orderCount)
let total1 = applyDiscount(to: item1, rate: 0.15)
let total2 = applyDiscount(to: item2)
let finalTotal = total1 + total2
logOrder("Final total: $\(finalTotal)", counter: &orderCount)
Saída:
TEXT 📖 Somente leitura[1] Item 1 subtotal: $79.98 [2] Item 2 subtotal: $49.97 [3] Final total: $112.94
❓ Perguntas Frequentes
P: Qual é a diferença entre rótulo de argumento e nome de parâmetro? R: O rótulo de argumento (nome externo) é usado no local da chamada. O nome do parâmetro (nome interno / nome local) é usado dentro do corpo da função. O primeiro serve para legibilidade no local da chamada; o segundo serve para semântica interna. Eles podem ser iguais ou diferentes. P: Como inout difere de uma variável global? R: Um parâmetro inout se comporta como uma variável local dentro da função e grava de volta no original apenas quando a função retorna. Uma variável global pode ser lida e escrita diretamente, mas reduz a manutenibilidade e testabilidade. inout é a escolha mais segura. P: Qual é a diferença entre parâmetros variáveis e de matriz? R: Os parâmetros variáveis não exigem a construção explícita de uma matriz no site de chamada — basta passar valores separados por vírgula. Os parâmetros da matriz requerem o formato
[1, 2, 3]. Variádico é mais conciso. P: Uma função pode ter mais de um parâmetro variádico? R: Não. Cada função pode ter no máximo um parâmetro variádico, e ele normalmente deve vir por último na lista de parâmetros. Se você precisar de múltiplos parâmetros de comprimento variável, considere usar parâmetros de array. P: O que uma função retorna quando a seta é omitida? R: Omitir-> Tipoequivale a retornarVoid(a tupla vazia()). O corpo da função pode omitir a instruçãoreturn. Por exemplo,func log() { print("log") }retornaVoid.
📖 Resumo
- Funções são definidas com a palavra-chave
func; a lista de parâmetros e o corpo formam a estrutura básica - Rótulos de argumento tornam as chamadas de função mais parecidas com linguagem natural — projete rótulos externos adequados para cada parâmetro
- Valores padrão de parâmetro reduzem código repetitivo de chamada e devem ficar no final da lista de parâmetros
- Parâmetros variádicos
...aceitam zero ou mais valores do mesmo tipo, expostos como um array dentro do corpo - Parâmetros inout permitem passagem por referência para modificar variáveis do chamador; prefixe com
&no local da chamada
📝 Exercícios
- Iniciante: Escreva uma função
saudarque aceitanome(String) esaudacao(String, padrão "Olá") e imprime uma saudação. Chame-a pelo menos duas vezes usando dois estilos diferentes de rótulo de argumento. - Intermediário: Escreva uma função
calcularIMCque aceitapeso(kg, Double) ealtura(m, Double), retornando o valor do IMC. Use rótulos de argumento para que o local da chamada leia comocalcularIMC(peso: 75, altura: 1.8). Adicione também um parâmetroinoutpara rastrear o número de chamadas. - Desafio: Escreva uma função
analisadorNotasque usa parâmetros variádicos para aceitar qualquer número de notas e retorna as notas mais alta, mais baixa e média. Use um parâmetroinoutpara manter um histórico de análise (adicione a contagem de cada análise a um array). Imprima o histórico no final.