iOS e Swift: Entendendo o uso de Generics: Por que e como utilizar?

iOS e Swift: Entendendo o uso de Generics: Por que e como utilizar?
Giovanna Moeller
Giovanna Moeller

Compartilhe

Resumindo

Neste artigo, vamos entender o conceito de generics, uma funcionalidade muito poderosa do Swift. Veremos também:

  • O conceito de "fortemente tipado" da linguagem Swift;
  • Como utilizar generics;
  • Por que utilizar generics.

Depois de ler esse artigo, você vai conseguir compreender e utilizar essa funcionalidade da linguagem Swift que resolve um certo tipo de problema. Vamos lá?

Banner da Escola de Mobile: Matricula-se na escola de Mobile. Junte-se a uma comunidade de mais de 500 mil estudantes. Na Alura você tem acesso a todos os cursos em uma única assinatura; tem novos lançamentos a cada semana; desafios práticos. Clique e saiba mais!

Swift, uma linguagem fortemente tipada

Antes de falarmos sobre generics, precisamos lembrar que Swift é uma linguagem fortemente tipada. Isso significa que, quando declaramos uma variável, precisamos já declarar qual o tipo de dado que será atribuído a essa variável. E, uma vez atribuído um certo tipo de dado, este não poderá ser alterado. Vamos ver alguns exemplos?

Vamos criar uma variável do tipo "inteiro" e atribuir o valor de 42. Em Swift, fazemos dessa maneira:

var numero: Int = 42

Veja que declaramos a variável numero e atribuímos o tipo de dado inteiro, através dos dois pontos. Mas, mesmo se omitirmos essa informação, o Swift é inteligente o suficiente para determinar o tipo de dado de forma automática, veja abaixo:

var numero = 42

Depois de determinar o tipo de dado, não podemos alterar esse tipo. Vamos tentar abaixo:

numero = "uma string qualquer"

Isso causará um erro de compilação e a sua aplicação não será executada, porque não é possível atribuir o valor a um tipo de dado diferente.

Concluindo, o Swift é uma linguagem fortemente tipada, em que uma variável sempre precisa estar atrelada a um tipo. Agora, vamos entender qual o problema que isso causa em determinadas situações.

Entendendo a motivação por trás do uso de Generics

Vamos começar, criando uma função que soma dois valores:

func soma(a: Int, b: Int) -> Int {
return a + b
}
let resultado = soma(a: 2, b: 3) // resultado será 5

Perceba que os parâmetros da função também precisam ter o seu tipo declarado. Se não declararmos um tipo para esses dados, acontece um erro de compilação e nossa aplicação não será executada.

Isso torna o nosso código muito limitado, pois podemos apenas somar dois números inteiros com essa função. Mas, e se precisarmos somar dois valores do tipo double? Precisamos criar outra função pra isso?

Se quisermos somar outros dois valores, só que agora do tipo float, precisaremos criar uma terceira função? Perceba que temos um problema: várias funções com o mesmo objetivo (somar dois valores), porém a única diferença é o tipo dos dados.

Extremamente desnecessária tanta repetição de código, já que o seu objetivo final é o mesmo, certo? É exatamente esse problema que o generics resolve. Vamos entender mais sobre isso a seguir!

Usando Generics

Generic, portanto, é uma funcionalidade da linguagem Swift que permite criar funções, tipos, protocolos, enums, entre outros, que não estão vinculados a nenhum tipo de dado específico, mas que podem ser usados com qualquer tipo que atenda a um determinado conjunto de requisitos.

Você provavelmente já até usou generics no seu código. Por exemplo, array é uma estrutura de dados genérica, que nos permite criar instâncias de qualquer tipo de dado, como Int, String, ou até mesmo um tipo de dado personalizado que a gente criou.

Veja abaixo dois exemplos de array:

let linguagens = ["Python", "C#", "Java", "Swift"]
let valores = [1, 4, 7]

O primeiro array é uma coleção de dados do tipo String, enquanto o segundo é do tipo Int.

Agora, voltando ao problema da função de soma que vimos anteriormente, como podemos resolver utilizando um tipo genérico, que nos permite somar diferentes tipos de dados? Veja abaixo o código que soluciona isso, e, logo depois, veremos a explicação:

func soma<T: Numeric>(a: T, b: T) -> T {
  return a + b
}

soma(a: 2.5, b: 3.0) // Resultado: 5.5
soma(a: 5, b: 4) // Resultado: 11

Ok, então vamos entender o que está acontecendo neste código. Primeiramente, criamos um tipo genérico de dados chamado T. T na verdade é uma convenção utilizada para determinar tipos genéricos. Você pode ler mais sobre isso aqui. A própria documentação do Swift, explicando sobre generics, também utiliza a letra T para definir esse tipo.

Veja que os parâmetros a e b são do tipo T, e o retorno da função também é do tipo T.

Agora não estamos mais presos a apenas um tipo de dado, como Int, Double ou Float. Perceba, também, que declaramos esse tipo logo após a palavra 'soma', abrindo com o sinal de <>. Também, declaramos que o tipo genérico T é, na verdade, um tipo Numeric, basicamente essa sintaxe é uma maneira de indicar qual tipo específico queremos limitar para o generics. Esse tipo Numeric engloba todos os números, como Int, Double, ou até mesmo Float.

Por isso que conseguimos passar qualquer valor agora para a função, independente de ser um inteiro ou um decimal. É exatamente esse o problema que o generic resolve: reutilizar o mesmo código para tipos diferentes. Agora, não precisamos mais declarar uma função para cada tipo de dado numérico, que gerava uma repetição de código desnecessária. E aí, gostou do generics?

Conclusão

Neste artigo, entendemos mais sobre o uso de generics, o porquê e como utilizar essa funcionalidade tão poderosa do Swift.

Você também pode complementar seus estudos lendo mais sobre esse assunto na documentação.

Se você tem interesse em outros artigos ou quer conhecer mais sobre o desenvolvimento iOS, basta me procurar aqui: Linkedin.

Quer saber mais sobre iOS? Confira nosso curso para iniciantes aqui na Alura: Swift parte 1 - Desenvolvendo para iOS no Xcode.

Até a próxima!

Giovanna Moeller
Giovanna Moeller

Desenvolvedora de Software e Criadora de Conteúdo @girl.coding

Veja outros artigos sobre Mobile