Erro E0308 do Rust: mismatched types (tipos incompatíveis)
O E0308 quer dizer que o Rust esperava um valor de um tipo, mas você entregou um valor de outro tipo. É provavelmente o erro que você mais vai ver em Rust, e a mensagem quase sempre mostra os dois tipos, então a correção costuma ser rápida. Para os outros erros desta série, veja Erros do compilador Rust.
A mensagem de erro
Seção intitulada “A mensagem de erro”error[E0308]: mismatched types --> src/main.rs:6:29 |6 | let user = User { name: "Ferris" }; | ^^^^^^^^ expected `String`, found `&str` |help: try using a conversion method |6 | let user = User { name: "Ferris".to_string() }; | ++++++++++++Em português: “tipos incompatíveis”. O compilador esperava uma String (expected String), encontrou um &str (found &str) e sugere um método de conversão, .to_string().
Este é o programa que gera o erro:
struct User { name: String,}
fn main() { let user = User { name: "Ferris" }; println!("{}", user.name);}O que significa
Seção intitulada “O que significa”Toda mensagem do E0308 tem o mesmo formato: expected A, found B (esperava A, encontrou B).
- Expected (esperado) é o tipo de que o Rust precisa naquele ponto. Ele vem de outro lugar: uma anotação de tipo, o parâmetro ou o retorno de uma função, um campo de struct ou outro ramo de um
if/match. - Found (encontrado) é o tipo do valor que você realmente escreveu ali.
No exemplo, o campo name foi declarado como String, então é isso que o Rust espera. Mas "Ferris" é um literal de string, e o tipo dele é &str. Os dois são parentes, mas não são o mesmo tipo.
Olhe também as linhas help:. No E0308, o compilador muitas vezes sugere a correção exata, como o .to_string() acima.
Por que o Rust faz isso
Seção intitulada “Por que o Rust faz isso”O Rust nunca converte tipos escondido. Em algumas linguagens, um número vira texto sem avisar, ou um número grande é cortado sem aviso para caber num tipo menor. Essas conversões escondidas causam bugs de verdade: dados perdidos, resultados errados, falhas bem longe do erro original.
Por isso, o Rust deixa toda conversão visível no código. Dá um pouco mais de digitação, mas quando você reler o código depois, vai ver exatamente onde um valor muda de tipo e se essa etapa pode falhar. Os tipos em si estão em Tipos de dados.
Como corrigir
Seção intitulada “Como corrigir”Cada correção abaixo começa com o formato do erro, para você ir direto à que combina com o seu.
Correção 1: Tire o ponto e vírgula do final
Seção intitulada “Correção 1: Tire o ponto e vírgula do final”error[E0308]: mismatched types --> src/main.rs:1:46 |1 | fn total_price(price: u32, quantity: u32) -> u32 { | ----------- ^^^ expected `u32`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression2 | price * quantity; | - help: remove this semicolon to return this valueSe aparecer found (), olhe a última linha da função. Em Rust, a última expressão de um bloco sem ponto e vírgula é o valor de retorno. Colocar ; transforma essa expressão numa instrução, e a função passa a retornar () (o tipo “nada”). O compilador diz isso com outras palavras: a função retorna () porque o corpo não tem expressão final nem return, e a ajuda pede para remover o ponto e vírgula. Apague o ;:
fn total_price(price: u32, quantity: u32) -> u32 { price * quantity // sem ponto e vírgula: este valor é retornado}
fn main() { println!("Total: {}", total_price(250, 3));}Saída:
Total: 750A mesma coisa acontece dentro de blocos if e braços de match. Mais em Funções.
Correção 2: Converta entre String e &str
Seção intitulada “Correção 2: Converta entre String e &str”String é uma string com dono, que pode crescer. &str é uma visão emprestada de um texto. A história completa está em Strings. Converter é curto nos dois sentidos:
- De
&strparaString:.to_string()ouString::from(...). - De
Stringpara&str: empreste com&(ou chame.as_str()).
O segundo caso aparece como expected &str, found String, normalmente quando você passa uma String para uma função que recebe &str.
struct User { name: String,}
fn greet(name: &str) { println!("Olá, {name}!");}
fn main() { // &str -> String: .to_string() ou String::from() let user = User { name: "Ferris".to_string() };
// String -> &str: empreste com & (ou chame .as_str()) greet(&user.name); greet(user.name.as_str());
let mut tags: Vec<String> = Vec::new(); tags.push(String::from("rust")); println!("{tags:?}");}Saída:
Olá, Ferris!Olá, Ferris!["rust"]Correção 3: Converta entre tipos numéricos
Seção intitulada “Correção 3: Converta entre tipos numéricos”error[E0308]: mismatched types --> src/main.rs:3:22 |3 | let count: i32 = names.len(); | --- ^^^^^^^^^^^ expected `i32`, found `usize` | | | expected due to thisAqui o compilador esperava um i32 por causa da anotação (expected due to this) e encontrou um usize. i32, i64, u32 e usize são todos tipos diferentes, e o Rust não mistura nenhum deles. Tamanhos e índices são sempre usize. Escolha uma conversão:
.into()(oui64::from(x)) quando a conversão nunca pode perder dados, como dei32parai64.i64::try_from(x)(ou.try_into()) quando o valor talvez não caiba. Ele retorna umResult, então você decide o que acontece se falhar.asé a conversão rápida. Ela nunca falha, mas corta sem avisar os valores que não cabem, então use só quando você sabe que o valor é pequeno.
fn average(total: i64, count: i64) -> i64 { total / count}
fn main() { let scores: Vec<i32> = vec![80, 95, 70]; let total: i32 = scores.iter().sum();
// i32 -> i64 sempre cabe, então .into() basta let total: i64 = total.into();
// usize -> i64 talvez não caiba, então try_from confere antes let count = i64::try_from(scores.len()).unwrap();
println!("Média: {}", average(total, count));
// `as` também funciona, mas corta sem avisar os valores que não cabem let players = scores.len() as i32; println!("{players} jogadores");}Saída:
Média: 813 jogadoresMuitas vezes, a correção mais simples é trocar a anotação: let count: usize = names.len();. As páginas Conversão de tipos e Conversões vão mais fundo.
Correção 4: Coloque dentro de Some ou tire o valor do Option
Seção intitulada “Correção 4: Coloque dentro de Some ou tire o valor do Option”error[E0308]: mismatched types --> src/main.rs:3:27 |3 | let position: usize = names.iter().position(|n| *n == "Ben"); | ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `Option<usize>` | | | expected due to thisOption<usize> não é um usize. É “talvez um usize, talvez nada”. Essa incompatibilidade aparece nos dois sentidos:
- Expected
T, foundOption<T>: você precisa tratar o caso “nada”, commatch,if letouunwrap_or(padrão). - Expected
Option<T>, foundT: sua função retornaOption, então embrulhe o valor:Some(10)em vez de10.
fn find_discount(code: &str) -> Option<u32> { if code == "SAVE10" { return Some(10); // T -> Option<T>: embrulhe em Some } None}
fn main() { let names = vec!["Ana", "Ben", "Cy"];
// Option<T> -> T: trate o caso "não encontrado"... match names.iter().position(|n| *n == "Ben") { Some(i) => println!("Ben está na posição {i}"), None => println!("Ben não está aqui"), }
// ...ou escolha um valor padrão com unwrap_or let discount: u32 = find_discount("HELLO").unwrap_or(0); println!("Desconto: {discount}%");}Saída:
Ben está na posição 1Desconto: 0%O compilador pode sugerir .expect("REASON"). Isso também funciona, mas derruba o programa quando o valor é None, então use só quando None realmente não pode acontecer. Veja Option.
Correção 5: Faça todos os ramos de if/else e match terem o mesmo tipo
Seção intitulada “Correção 5: Faça todos os ramos de if/else e match terem o mesmo tipo”error[E0308]: `if` and `else` have incompatible types --> src/main.rs:3:52 |3 | let label = if stock > 0 { "in stock" } else { stock }; | ---------- ^^^^^ expected `&str`, found integer | | | expected because of thisEm português: “if e else têm tipos incompatíveis”. Quando um if ou um match produz um valor, o Rust precisa saber qual é o tipo único dele. Por isso, todos os ramos precisam produzir o mesmo tipo. O primeiro ramo define o que se espera, e o erro aponta para o ramo que discorda. No match, a mensagem diz “match arms have incompatible types” (os braços do match têm tipos incompatíveis). Faça o ramo diferente concordar com os outros:
fn status_text(code: u16) -> String { match code { 200 => "OK".to_string(), 404 => "Not Found".to_string(), _ => format!("Código desconhecido {code}"), // todos os braços são String }}
fn main() { let stock = 0; let label = if stock > 0 { "in stock" } else { "sold out" }; // os dois são &str println!("{label}");
println!("{}", status_text(404)); println!("{}", status_text(418));}Saída:
sold outNot FoundCódigo desconhecido 418Aqui um dos braços precisava de format!, que cria uma String, então os outros braços também viraram String. Deixamos "in stock" e "sold out" em inglês para combinar com a mensagem de erro acima. Veja If…Else e Match.
Onde você costuma ver esse erro
Seção intitulada “Onde você costuma ver esse erro”- Lendo a entrada do usuário.
let age: u32 = input.trim();dá “expectedu32, found&str”. Texto não é número. Correção: converta com parse:let age: u32 = input.trim().parse().unwrap();(ou trate o erro, veja Result). - Colocando literais num
Vec<String>.tags.push("rust")dá “expectedString, found&str”. Correção:tags.push("rust".to_string()), ou use umVec<&str>se todas as strings forem literais. - Contas com tipos numéricos misturados.
total + n, comtotalsendoi64ensendoi32, dá E0308 (e muitas vezes um E0277 junto). Correção: converta um dos lados antes:total + i64::from(n).
Erros relacionados
Seção intitulada “Erros relacionados”- E0277: trait bound not satisfied: costuma aparecer junto com o E0308, por exemplo quando você soma um
i64com umi32. - E0599: no method found: você chamou um método que não existe nesse tipo, muitas vezes porque o valor tem um tipo diferente do que você imaginava.
- E0425: cannot find value in this scope: um nome que o Rust simplesmente não conhece.
- Todos os erros do compilador: a lista completa de páginas de erro.
Teste o que aprendeu
Seção intitulada “Teste o que aprendeu”Teste o que aprendeu
1. Uma função diz -> i32, mas o erro diz "expected i32, found ()". Qual é a causa mais provável?
2. Uma função recebe &str e você tem let name = String::from("Ana");. Como você passa o valor?
3. Qual conversão nunca perde dados sem avisar?
Pontuação: 0 / 3
Para saber mais
Seção intitulada “Para saber mais”- E0308 — Rust error codes index (em inglês): a explicação oficial deste erro.
- Functions with Return Values — The Rust Book (em inglês): por que um ponto e vírgula no final muda o que a função retorna.
- Storing UTF-8 Text with Strings — The Rust Book (em inglês): como
Stringe&strse relacionam e como converter entre os dois. - Conversion — Rust by Example (em inglês):
From,Into,TryFromeTryIntocom exemplos curtos. - Option — documentação da biblioteca padrão (em inglês): todos os métodos para tirar um valor de um
Option, comounwrap_oremap.