E0107: Argumentos Genéricos Incorretos no Rust

Como resolver o erro E0107 do Rust: número incorreto de argumentos genéricos. Aprenda a usar parâmetros de tipo, lifetime e const generics corretamente.

E0107: Argumentos Genéricos Incorretos

O erro E0107 ocorre quando você fornece o número errado de argumentos genéricos (tipo, lifetime ou const) ao usar um tipo ou função genérica. É como chamar uma função com o número errado de argumentos, mas para parâmetros de tipo.

A Mensagem de Erro

error[E0107]: this struct takes 2 generic arguments but 1 generic argument was supplied
 --> src/main.rs:3:16
  |
3 |     let mapa: HashMap<String> = HashMap::new();
  |               ^^^^^^^ ------- supplied 1 generic argument
  |               |
  |               expected 2 generic arguments
  |
note: struct defined here, with 2 generic parameters: `K`, `V`

Outra variação — argumentos demais:

error[E0107]: this struct takes 1 generic argument but 2 generic arguments were supplied
 --> src/main.rs:3:16
  |
3 |     let lista: Vec<i32, String> = Vec::new();
  |                ^^^      ------ help: remove this generic argument
  |                |
  |                expected 1 generic argument

O Que Significa

Tipos genéricos no Rust são definidos com um número específico de parâmetros de tipo. Quando você usa o tipo, precisa fornecer exatamente o número correto:

  • Vec<T> — 1 parâmetro de tipo
  • HashMap<K, V> — 2 parâmetros de tipo
  • Result<T, E> — 2 parâmetros de tipo
  • Option<T> — 1 parâmetro de tipo

Se você fornece menos ou mais parâmetros que o esperado, o compilador rejeita o código. Em alguns casos, o compilador pode inferir os tipos automaticamente (e você não precisa especificá-los), mas quando você começa a anotar, precisa fornecer todos.

Código com Erro

use std::collections::HashMap;

fn main() {
    // ERRO: HashMap precisa de 2 argumentos (chave e valor)
    let mapa: HashMap<String> = HashMap::new();

    // ERRO: Vec precisa de apenas 1 argumento
    let lista: Vec<i32, f64> = Vec::new();

    // ERRO: Option precisa de 1 argumento
    let valor: Option = Some(42);
}

Com funções genéricas:

fn converter<T, U>(valor: T) -> U {
    todo!()
}

fn main() {
    // ERRO: a função precisa de 2 argumentos genéricos
    let resultado = converter::<i32>(42);
}

Com lifetimes:

struct Referencia<'a, 'b> {
    primeiro: &'a str,
    segundo: &'b str,
}

fn criar(a: &str, b: &str) -> Referencia {
    // ERRO: Referencia precisa de 2 lifetimes
    Referencia { primeiro: a, segundo: b }
}

Como Resolver

Solução 1: Fornecer o Número Correto de Argumentos

use std::collections::HashMap;

fn main() {
    // HashMap<K, V> — 2 argumentos
    let mapa: HashMap<String, i32> = HashMap::new();

    // Vec<T> — 1 argumento
    let lista: Vec<i32> = Vec::new();

    // Result<T, E> — 2 argumentos
    let resultado: Result<String, std::io::Error> = Ok("sucesso".to_string());

    // Option<T> — 1 argumento
    let valor: Option<i32> = Some(42);
}

Solução 2: Deixar o Compilador Inferir os Tipos

Em muitos casos, você não precisa especificar os tipos — o compilador infere:

use std::collections::HashMap;

fn main() {
    // O compilador infere HashMap<&str, i32> pelo uso
    let mut mapa = HashMap::new();
    mapa.insert("chave", 42);

    // O compilador infere Vec<i32> pelos elementos
    let lista = vec![1, 2, 3];

    // Inferência parcial com _ (turbofish parcial)
    let numeros: Vec<_> = (1..10).collect();
}

Solução 3: Usar Turbofish para Funções Genéricas

A sintaxe ::<> (turbofish) especifica argumentos genéricos em chamadas de função:

fn main() {
    // Todos os argumentos genéricos
    let resultado = "42".parse::<i32>().unwrap();

    // Collect com tipo especificado
    let numeros: Vec<i32> = (1..5).collect();
    // Ou com turbofish:
    let numeros = (1..5).collect::<Vec<i32>>();
}

Solução 4: Corrigir Lifetimes

struct Referencia<'a, 'b> {
    primeiro: &'a str,
    segundo: &'b str,
}

// Especifique todos os lifetimes necessários
fn criar<'a, 'b>(a: &'a str, b: &'b str) -> Referencia<'a, 'b> {
    Referencia { primeiro: a, segundo: b }
}

Ou simplifique usando um único lifetime quando possível:

struct Referencia<'a> {
    primeiro: &'a str,
    segundo: &'a str,
}

fn criar<'a>(a: &'a str, b: &'a str) -> Referencia<'a> {
    Referencia { primeiro: a, segundo: b }
}

Solução 5: Tipos com Default Genéricos

Alguns tipos têm parâmetros genéricos com valores padrão. HashMap, por exemplo, tem um terceiro parâmetro opcional para o hasher:

use std::collections::HashMap;

// HashMap<K, V, S = RandomState>
// Normalmente usamos apenas K e V:
let mapa: HashMap<String, i32> = HashMap::new();

// Mas podemos especificar um hasher customizado:
use std::hash::BuildHasherDefault;
use std::collections::hash_map::DefaultHasher;
let mapa: HashMap<String, i32, BuildHasherDefault<DefaultHasher>> = HashMap::default();

Referência Rápida de Tipos Genéricos Comuns

TipoParâmetrosExemplo
Vec<T>1 tipoVec<String>
Option<T>1 tipoOption<i32>
Result<T, E>2 tiposResult<String, Error>
HashMap<K, V>2 tiposHashMap<String, Vec<i32>>
BTreeMap<K, V>2 tiposBTreeMap<i32, String>
Box<T>1 tipoBox<dyn Error>
Rc<T>1 tipoRc<String>
Arc<T>1 tipoArc<Mutex<Vec<i32>>>
Cow<'a, B>1 lifetime + 1 tipoCow<'a, str>

Veja Também