Cada linguagem de programação possui ferramentas para lidar de forma eficaz com a duplicação de conceitos. No Rust, uma dessas ferramentas são os genéricos. Os genéricos são substitutos abstratos para tipos concretos ou outras propriedades. Quando estamos escrevendo código, podemos expressar o comportamento dos genéricos ou como eles se relacionam com outros genéricos sem saber o que estará em seu lugar ao compilar e executar o código.
Semelhante à maneira como uma função usa parâmetros com valores desconhecidos para executar o mesmo código em vários valores concretos, as funções podem usar parâmetros de algum tipo genérico em vez de um tipo concreto, como i32
ou String
. Na verdade, já usamos os genéricos no Capítulo 6 com Option<T>
, no Capítulo 8 com Vec<T>
e HashMap<K, V>
e no Capítulo 9 com Result<T, E>
. Neste capítulo, você explorará como definir seus próprios tipos, funções e métodos com genéricos!
Primeiro, vamos revisar como extrair uma função para reduzir a duplicação de código. A seguir, usaremos a mesma técnica para fazer uma função genérica a partir de duas funções que diferem apenas nos tipos de seus parâmetros. Também explicaremos como usar tipos genéricos em definições de struct e enum.
Em seguida, você aprenderá como usar características para definir o comportamento de uma forma genérica. Você pode combinar características com tipos genéricos para restringir um tipo genérico apenas aos tipos que têm um comportamento específico, em oposição a qualquer tipo.
Finalmente, discutiremos os tempos de vida, uma variedade de genéricos que fornecem ao compilador informações sobre como as referências se relacionam entre si. Os tempos de vida nos permitem pegar valores emprestados em muitas situações, enquanto ainda permitem que o compilador verifique se as referências são válidas.
Removendo Duplicação Extraindo uma Função
Antes de mergulhar na sintaxe dos genéricos, vamos primeiro ver como remover a duplicação que não envolve tipos genéricos extraindo uma função. Em seguida, aplicaremos essa técnica para extrair uma função genérica! Da mesma forma que você reconhece o código duplicado para extrair em uma função, você começará a reconhecer o código duplicado que pode usar genéricos.
Considere um programa curto que encontra o maior número em uma lista, conforme mostrado na Listagem 10-1.
Nome do arquivo: src/main.rs
Este código armazena uma lista de inteiros na variável lista_de_numeros
e coloca o primeiro número da lista em uma variável chamada maior
. Em seguida, ele itera por todos os números da lista e, se o número atual for maior do que o número armazenado em maior
, ele substitui o número dessa variável. No entanto, se o número atual for menor ou igual ao maior número visto até agora, a variável não muda e o código passa para o próximo número na lista. Depois de considerar todos os números da lista, maior
deve conter o maior número, que neste caso é 100.
Para encontrar o maior número em duas listas diferentes de números, podemos duplicar o código da Listagem 10-1 e usar a mesma lógica em dois locais diferentes no programa, conforme mostrado na Listagem 10-2.
Nome do arquivo: src/main.rs
fn main() {
let lista_de_numeros = vec![34, 50, 25, 100, 65];
let mut maior = lista_de_numeros[0];
for numero in lista_de_numeros {
if numero > maior {
maior = numero;
}
}
println!("O maior número é {}", maior);
let lista_de_numeros = vec![102, 34, 6000, 89, 54, 2, 43, 8];
let mut maior = lista_de_numeros[0];
for numero in lista_de_numeros {
if numero > maior {
maior = numero;
}
}
println!("O maior número é {}", maior);
}
Embora esse código funcione, duplicá-lo é tedioso e sujeito a erros. Também temos que atualizar o código em vários lugares quando quisermos alterá-lo.
Para eliminar essa duplicação, podemos criar uma abstração definindo uma função que opera em qualquer lista de inteiros fornecidos a ela em um parâmetro. Essa solução torna nosso código mais claro e nos permite expressar o conceito de encontrar o maior número em uma lista de maneira abstrata.
Na Listagem 10-3, extraímos o código que encontra o maior número em uma função chamada maior
. Ao contrário do código da Listagem 10-1, que pode localizar o maior número em apenas uma lista específica, este programa pode localizar o maior número em duas listas diferentes.
Nome do arquivo: src/main.rs
A função maior
tem um parâmetro chamado list
, que representa qualquer fatia concreta de valores i32
que podemos passar para a função. Como resultado, quando chamamos a função, o código é executado nos valores específicos que passamos.
Em suma, aqui estão as etapas que seguimos para alterar o código da Listagem 10-2 para a Listagem 10-3:
- Identifique o código duplicado.
- Extraia o código duplicado no corpo da função e especifique as entradas e os valores de retorno desse códigona assinatura da função.
- Atualize as duas instâncias de código duplicado para chamar a função.
A seguir, usaremos essas mesmas etapas com os genéricos para reduzir a duplicação de código de maneiras diferentes. Da mesma forma que o corpo da função pode operar em um abstrato em list
em vez de valores específicos, os genéricos permitem que o código opere em tipos abstratos.
Por exemplo, digamos que temos duas funções: uma que encontra o maior item em uma fatia de valores i32
e outra que encontra o maior item em uma fatia de valores char
. Como eliminaríamos essa duplicação? Vamos descobrir!
Traduzido por Acervo Lima. O original pode ser acessado aqui.
0 comentários:
Postar um comentário