Pular para o conteúdo principal

Recursos Avançados

Generics

Generics permitem criar código reutilizável que funciona com diferentes tipos:

class Caixa<T> {
T conteudo;

Caixa(this.conteudo);

T obter() {
return conteudo;
}
}

var caixaString = Caixa<String>("Olá");
var caixaInt = Caixa<int>(42);

print(caixaString.obter()); // "Olá"
print(caixaInt.obter()); // 42

Com funções:

T primeiro<T>(List<T> lista) {
return lista[0];
}

String nome = primeiro<String>(['João', 'Maria']);
int numero = primeiro<int>([1, 2, 3]);

Typedefs

Typedefs criam aliases (apelidos) para tipos de função:

typedef Operacao = int Function(int, int);

int somar(int a, int b) => a + b;
int multiplicar(int a, int b) => a * b;

void executar(Operacao op, int a, int b) {
print(op(a, b));
}

executar(somar, 5, 3); // 8
executar(multiplicar, 4, 2); // 8

Exercícios

  1. Generics em classes: Crie uma classe genérica Pilha<T> que armazene elementos em uma lista. Implemente métodos empilhar, desempilhar e topo. Teste com diferentes tipos (String, int).

  2. Generics em funções: Crie uma função genérica trocar que receba uma lista e dois índices, e troque os elementos nessas posições. A função deve funcionar com qualquer tipo.

  3. Typedefs: Crie um typedef Comparador para funções que comparam dois números. Crie funções que encontrem o maior e menor número em uma lista usando esse comparador.

  4. Generics com restrições: Crie uma classe genérica Caixa que só aceite tipos numéricos (int ou double). Adicione um método que some todos os valores.

  5. Generics aninhados: Crie uma função genérica que receba uma lista de listas e retorne uma lista "achatada" (flatten) de qualquer tipo.

Soluções

Ver solução do exercício 1
class Pilha<T> {
List<T> _elementos = [];

void empilhar(T elemento) {
_elementos.add(elemento);
}

T? desempilhar() {
if (_elementos.isEmpty) {
return null;
}
return _elementos.removeLast();
}

T? topo() {
if (_elementos.isEmpty) {
return null;
}
return _elementos.last;
}

bool get vazia => _elementos.isEmpty;
int get tamanho => _elementos.length;
}

void main() {
var pilhaString = Pilha<String>();
pilhaString.empilhar("primeiro");
pilhaString.empilhar("segundo");
print(pilhaString.topo()); // segundo
print(pilhaString.desempilhar()); // segundo

var pilhaInt = Pilha<int>();
pilhaInt.empilhar(1);
pilhaInt.empilhar(2);
pilhaInt.empilhar(3);
print(pilhaInt.topo()); // 3
}
Ver solução do exercício 2
void trocar<T>(List<T> lista, int indice1, int indice2) {
if (indice1 >= 0 && indice1 < lista.length &&
indice2 >= 0 && indice2 < lista.length) {
T temp = lista[indice1];
lista[indice1] = lista[indice2];
lista[indice2] = temp;
}
}

void main() {
List<int> numeros = [1, 2, 3, 4, 5];
trocar(numeros, 0, 4);
print(numeros); // [5, 2, 3, 4, 1]

List<String> palavras = ["a", "b", "c"];
trocar(palavras, 0, 2);
print(palavras); // [c, b, a]
}
Ver solução do exercício 3
typedef Comparador = int Function(int, int);

int compararMaior(int a, int b) => a.compareTo(b);
int compararMenor(int a, int b) => b.compareTo(a);

int? encontrar(List<int> numeros, Comparador comparador) {
if (numeros.isEmpty) return null;

int resultado = numeros[0];
for (int num in numeros) {
if (comparador(num, resultado) > 0) {
resultado = num;
}
}
return resultado;
}

void main() {
List<int> numeros = [3, 1, 4, 1, 5, 9, 2, 6];

int? maior = encontrar(numeros, compararMaior);
print("Maior: $maior"); // 9

int? menor = encontrar(numeros, compararMenor);
print("Menor: $menor"); // 1
}
Ver solução do exercício 4
class Caixa<T extends num> {
List<T> valores = [];

void adicionar(T valor) {
valores.add(valor);
}

num somar() {
num soma = 0;
for (T valor in valores) {
soma += valor;
}
return soma;
}
}

void main() {
var caixaInt = Caixa<int>();
caixaInt.adicionar(10);
caixaInt.adicionar(20);
caixaInt.adicionar(30);
print(caixaInt.somar()); // 60

var caixaDouble = Caixa<double>();
caixaDouble.adicionar(1.5);
caixaDouble.adicionar(2.5);
print(caixaDouble.somar()); // 4.0
}
Ver solução do exercício 5
List<T> achatar<T>(List<List<T>> listas) {
List<T> resultado = [];
for (List<T> lista in listas) {
resultado.addAll(lista);
}
return resultado;
}

void main() {
List<List<int>> numeros = [
[1, 2, 3],
[4, 5],
[6, 7, 8, 9]
];
List<int> achatado = achatar(numeros);
print(achatado); // [1, 2, 3, 4, 5, 6, 7, 8, 9]

List<List<String>> palavras = [
["a", "b"],
["c", "d", "e"]
];
List<String> palavrasAchatadas = achatar(palavras);
print(palavrasAchatadas); // [a, b, c, d, e]
}