Generic (programação genérica) — é um mecanismo do Swift que permite escrever tipos e funções com um tipo parametrizado
Principais Conclusões
Generic (tipo genérico) — é uma construção sintática do Swift que permite escrever código flexível e reutilizável com parametrização de tipo. Em vez de um tipo concreto, um placeholder é escrito entre colchetes angulares — geralmente
Sem generics, você teria que escrever funções separadas para cada tipo: swapInts, swapStrings, swapDates. Uma função genérica swap substitui todas as três variantes com uma única declaração. Isso reduz duplicação, melhora a legibilidade e diminui a chance de erros ao copiar código.
func swapValues<T>(_ a: inout T, _ b: inout T) {
let temp = a
a = b
b = temp
}
var x = 10
var y = 20
swapValues(&x, &y)
O compilador Swift gera código especializado para cada uso concreto de um generic. Isso significa que a função genérica swapValues
Funções genéricas são funções que aceitam um ou mais parâmetros de tipo. Os parâmetros de tipo são especificados após o nome da função entre colchetes angulares:
Uma função pode ter múltiplos parâmetros genéricos. Por exemplo, a função findKey
func findKey<K: Hashable, V>(
for value: V,
in dictionary: [K: V]
) -> K? where V: Equatable {
for (key, dictValue) in dictionary {
if dictValue == value {
return key
}
}
return nil
}
As restrições K: Hashable e where V: Equatable garantem que findKey só pode ser chamada com um dicionário cujas chaves sejam hashable e valores equatable. Tais restrições não são burocracia, mas necessidade: sem Hashable não se pode indexar uma busca por chave, sem Equatable não se pode comparar value com dictValue.
where — é uma palavra-chave do Swift que impõe restrições adicionais aos parâmetros genéricos. Ao contrário de simplesmente especificar um protocolo entre colchetes angulares (
A cláusula where é escrita após a assinatura da função ou tipo, antes da chave de abertura. Em where você pode especificar que T: Comparable & Hashable (conforme a dois protocolos simultaneamente), ou que T.U == Int (concretizar um associated type).
protocol Container {
associatedtype Item
mutating func append(_ item: Item)
var count: Int { get }
}
extension Container where Item: Comparable {
func isSorted() -> Bool {
// Implementation available only if Item: Comparable
return true
}
}
A extensão com where adiciona métodos apenas para aqueles tipos que satisfazem a condição. Container
Associated Types (tipos associados) — são uma forma de tornar um protocolo genérico sem especificar um tipo concreto no estágio de declaração. Em vez de
Usando where você pode estabelecer relações entre associated types de diferentes protocolos. Por exemplo, você pode exigir que o Item de um protocolo corresponda ao Iterator.Element de outro. Isso garante compatibilidade de tipo no nível do compilador.
protocol StackProtocol {
associatedtype Element
mutating func push(_ item: Element)
mutating func pop() -> Element?
}
struct IntStack: StackProtocol {
typealias Element = Int
private var items: [Int] = []
mutating func push(_ item: Int) { items.append(item) }
mutating func pop() -> Int? { items.popLast() }
}
IntStack concretiza Element como Int usando typealias. O compilador verifica se todos os requisitos do protocolo são atendidos com este tipo. Sem associated types, você teria que escrever StackProtocol
Extensões genéricas permitem adicionar métodos a um tipo genérico com restrições adicionais. Este é o padrão de “conformidade condicional”, onde um tipo ganha funcionalidade apenas sob certas condições. Subscritos também podem ser genéricos.
Um subscrito pode ser genérico: ele aceita parâmetros genéricos entre colchetes angulares. Isso é útil para acesso seguro a coleções com índices arbitrários, onde o índice pode ser de diferentes tipos.
extension Array where Element: Numeric {
func sum() -> Element {
return reduce(0, +)
}
}
extension Array {
subscript<Indices: Sequence>(indices: Indices) -> [Element]
where Indices.Element == Int {
return indices.map { self[$0] }
}
}
Esta construção fornece composição poderosa: o método sum aparece apenas em arrays numéricos, e o subscrito com índices arbitrários funciona com qualquer sequência de índices inteiros. O compilador gerencia a visibilidade desses membros com base nas condições where.
Erros ao usar genéricos geralmente estão relacionados a restrições incorretas ou à tentativa de usar genéricos onde um tipo concreto é necessário. Vamos ver três cenários comuns que os desenvolvedores enfrentam.
Adicionar parâmetros genéricos onde um tipo concreto é suficiente é um antipadrão. Se uma função sempre trabalha com String, não há necessidade de torná-la
Chamar um método em um parâmetro genérico sem especificar que o método existe é um erro.
// ❌ Error: value has no count method
func countElements<T>>(value: T) -> Int { value.count }
// ✅ Works: T: Collection guarantees count exists
func countElements<T: Collection>(value: T) -> Int { value.count }
O erro é claro: o genérico
Perguntas Frequentes
Generic é uma forma de escrever código que funciona com qualquer tipo, sem duplicar a mesma lógica para Int, String e outros tipos. Em vez de um tipo concreto, um placeholder
Generic preserva informação sobre o tipo concreto em tempo de compilação, permitindo ao compilador verificar tipos e gerar código otimizado. Any é apagamento de tipo: qualquer valor pode ser passado, mas o tipo se perde, e é necessário casting (as?).
Use a sintaxe T: SomeProtocol entre colchetes angulares ou uma cláusula separada where T: SomeProtocol. As restrições garantem que o parâmetro genérico suporta métodos e propriedades específicos.
Associated Type (associatedtype) é um placeholder para um tipo dentro de um protocolo. O protocolo não especifica um tipo concreto, mas declara um associatedtype, que é concretizado na implementação: Array tem Element, Dictionary tem Key e Value.
Swift compila código genérico em versões especializadas para cada tipo concreto. Na prática, uma função genérica para Int não é mais lenta que uma função escrita à mão para Int. Não há sobrecarga de abstração.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também