Generics e tipagem em Swift: como escrever código que trabalha por você

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Por que sem genéricos seu código Swift rapidamente se transformará em espaguete

\n\n

Imagine que você está escrevendo um aplicativo de entrega de pizza. Você precisa processar pedidos, clientes, entregadores — e toda vez escrever o mesmo código para ordenação, busca ou filtragem, mudando apenas o tipo de dados? Parece o pesadelo de qualquer desenvolvedor. É aqui que entram em cena os Generics em Swift — uma ferramenta poderosa que permite escrever código flexível e reutilizável sem sacrificar a segurança de tipos.

\n\n

Neste artigo, não vamos apenas passar pela sintaxe. Vamos analisar como a tipagem em Swift e os genéricos trabalham juntos para que seu código não seja apenas bonito, mas também confiável. Você aprenderá como se livrar do copia e cola, como usar protocol com associatedtype e por que as cláusulas where são suas melhores amigas.

\n\n

O que são Generics e por que eles mudam as regras do jogo

\n\n

Generics (genéricos, tipos genéricos) são um mecanismo que permite escrever funções, estruturas, classes e enumerações que funcionam com qualquer tipo de dado que satisfaça certas condições. Em vez de escrever três versões de uma função para Int, String e Double, você escreve uma que funciona com qualquer tipo.

\n\n

Em Swift, a tipagem é forte e estática. Isso significa que o compilador verifica os tipos em tempo de compilação. Os Generics não quebram essa regra — eles a tornam mais flexível. O compilador infere o tipo específico ao chamar a função, mas as verificações permanecem.

\n\n

Primeiro exemplo: função sem genéricos

\n\n
// Ruim: três funções para três tipos\nfunc swapInts(_ a: inout Int, _ b: inout Int) {\n    let temp = a\n    a = b\n    b = temp\n}\n\nfunc swapStrings(_ a: inout String, _ b: inout String) {\n    let temp = a\n    a = b\n    b = temp\n}\n\nfunc swapDoubles(_ a: inout Double, _ b: inout Double) {\n    let temp = a\n    a = b\n    b = temp\n}
\n\n

Agora — a solução elegante com genéricos:

\n\n
// Bom: uma função para todos os tipos\nfunc swapValues<T>(_ a: inout T, _ b: inout T) {\n    let temp = a\n    a = b\n    b = temp\n}\n\n// Uso:\nvar x = 10\nvar y = 20\nswapValues(&x, &y) // T = Int\n\nvar name1 = "Alice"\nvar name2 = "Bob"\nswapValues(&name1, &name2) // T = String
\n\n

Viu a mágica? <T> é um placeholder (marcador) de tipo. O compilador substitui pelo tipo real na chamada. Essa é a base da programação genérica em Swift.

\n\n

Tipos genéricos: criando sua própria pilha universal

\n\n

Os genéricos em Swift funcionam não apenas com funções, mas também com tipos inteiros. Vamos criar uma estrutura Stack — o exemplo clássico de estrutura de dados LIFO (Last In, First Out).

\n\n
struct Stack<Element> {\n    private var items: [Element] = []\n    \n    mutating func push(_ item: Element) {\n        items.append(item)\n    }\n    \n    mutating func pop() -> Element? {\n        return items.popLast()\n    }\n    \n    func peek() -> Element? {\n        return items.last\n    }\n    \n    var count: Int {\n        return items.count\n    }\n}\n\n// Uso:\nvar intStack = Stack<Int>()\nintStack.push(1)\nintStack.push(2)\nintStack.push(3)\nprint(intStack.pop() ?? 0) // 3\n\nvar stringStack = Stack<String>()\nstringStack.push("Swift")\nstringStack.push("Generics")\nprint(stringStack.peek() ?? "") // "Generics"
\n\n

Observe: o tipo Element é especificado entre colchetes angulares na declaração da estrutura. Ao criar uma instância, o concretizamos — Stack<Int> ou Stack<String>. O compilador garante que você não possa acidentalmente colocar uma string em uma pilha de inteiros.

\n\n

Protocol com associatedtype: genéricos para protocolos

\n\n

Em Swift, os protocolos não podem ter parâmetros genéricos diretamente. Em vez disso, us

Blogs

Book Recommendations