---
title: "E0308: Tipos Incompatíveis no Rust"
url: "https://rustlang.com.br/erros/e0308-tipos-incompativeis/"
markdown_url: "https://rustlang.com.br/erros/e0308-tipos-incompativeis.MD"
description: "Como resolver o erro E0308 do Rust: tipos incompatíveis (mismatched types). Veja os casos mais comuns como String vs \u0026str, i32 vs usize e como converter entre tipos."
date: "2026-02-23"
author: "Equipe Rust Brasil"
---

# E0308: Tipos Incompatíveis no Rust

Como resolver o erro E0308 do Rust: tipos incompatíveis (mismatched types). Veja os casos mais comuns como String vs &str, i32 vs usize e como converter entre tipos.


# E0308: Tipos Incompatíveis

O erro **E0308** é um dos mais frequentes no Rust e ocorre quando o compilador espera um tipo, mas encontra outro. O sistema de tipos do Rust é forte e estático — não existe conversão implícita entre tipos, mesmo entre `i32` e `i64` ou `String` e `&str`.

## A Mensagem de Erro

```
error[E0308]: mismatched types
 --> src/main.rs:3:20
  |
3 |     let nome: &str = String::from("Rust");
  |               ----   ^^^^^^^^^^^^^^^^^^^^^ expected `&str`, found `String`
  |               |
  |               expected due to this
```

Outra variação comum:

```
error[E0308]: mismatched types
 --> src/main.rs:5:18
  |
5 |     let indice: i32 = vec.len();
  |                 ---   ^^^^^^^^^ expected `i32`, found `usize`
  |                 |
  |                 expected due to this
```

## O Que Significa

O Rust exige que os tipos sejam **exatamente** compatíveis. Diferente de linguagens como JavaScript ou Python, não há coerção automática entre tipos. Isso previne bugs sutis como:

- Perda de precisão ao converter `f64` para `f32`
- Overflow ao converter `i64` para `i32`
- Problemas de memória ao confundir `String` (owned) com `&str` (referência)

Os casos mais comuns deste erro são:

1. **`String` vs `&str`** — O par mais confuso para iniciantes
2. **`i32` vs `usize`** — Retorno de `.len()` é `usize`
3. **`Option<T>` vs `T`** — Esqueceu de desempacotar o `Option`
4. **`Result<T, E>` vs `T`** — Esqueceu de tratar o `Result`
5. **`()` vs outro tipo** — Função sem retorno explícito retorna `()`

## Código com Erro

### String vs &str

```rust
fn saudacao(nome: &str) -> String {
    format!("Olá, {}!", nome)
}

fn main() {
    let nome = String::from("Rust");
    let msg: &str = saudacao(&nome);  // ERRO: esperava &str, recebeu String
}
```

### i32 vs usize

```rust
fn main() {
    let numeros = vec![1, 2, 3, 4, 5];
    let indice: i32 = numeros.len();  // ERRO: len() retorna usize
}
```

### Option vs valor direto

```rust
fn main() {
    let numeros = vec![10, 20, 30];
    let primeiro: &i32 = numeros.get(0);  // ERRO: get() retorna Option<&i32>
}
```

## Como Resolver

### Solução 1: String e &str — Conversões Corretas

```rust
// &str para String
let owned: String = "texto".to_string();
let owned: String = String::from("texto");
let owned: String = "texto".to_owned();

// String para &str
let s = String::from("texto");
let referencia: &str = &s;        // coerção automática (deref)
let referencia: &str = s.as_str(); // explícito
```

Corrigindo o exemplo anterior:

```rust
fn saudacao(nome: &str) -> String {
    format!("Olá, {}!", nome)
}

fn main() {
    let nome = String::from("Rust");
    let msg: String = saudacao(&nome);  // Tipo correto agora
    println!("{}", msg);
}
```

### Solução 2: Conversões Numéricas com `as` ou `try_into()`

```rust
fn main() {
    let numeros = vec![1, 2, 3, 4, 5];

    // Opção 1: use o tipo correto
    let tamanho: usize = numeros.len();

    // Opção 2: converta com `as`
    let tamanho_i32: i32 = numeros.len() as i32;

    // Opção 3: conversão segura com try_into
    use std::convert::TryInto;
    let tamanho_i32: i32 = numeros.len().try_into().unwrap();
}
```

**Dica:** Prefira `try_into()` sobre `as` quando há risco de overflow. O `as` trunca silenciosamente, enquanto `try_into()` retorna `Result` e permite tratamento de erro.

### Solução 3: Desempacotar Option e Result

```rust
fn main() {
    let numeros = vec![10, 20, 30];

    // Opção 1: unwrap (panic se None)
    let primeiro: &i32 = numeros.get(0).unwrap();

    // Opção 2: valor padrão
    let primeiro: &i32 = numeros.get(0).unwrap_or(&0);

    // Opção 3: if let
    if let Some(primeiro) = numeros.get(0) {
        println!("Primeiro: {}", primeiro);
    }

    // Opção 4: match
    match numeros.get(0) {
        Some(valor) => println!("Valor: {}", valor),
        None => println!("Lista vazia"),
    }
}
```

### Solução 4: Garantir Retorno Correto em Funções

```rust
// ERRO: a função retorna () no branch else
fn verificar(n: i32) -> bool {
    if n > 0 {
        true
    }
    // Falta o `else` — retorno implícito é ()
}

// CORRETO:
fn verificar(n: i32) -> bool {
    n > 0  // Expressão que retorna bool
}
```

## Tabela de Conversões Comuns

| De | Para | Método |
|---|---|---|
| `&str` | `String` | `.to_string()`, `String::from()` |
| `String` | `&str` | `&s`, `.as_str()` |
| `i32` | `i64` | `.into()`, `as i64` |
| `i64` | `i32` | `.try_into()`, `as i32` |
| `usize` | `i32` | `.try_into()`, `as i32` |
| `&[T]` | `Vec<T>` | `.to_vec()` |
| `Vec<T>` | `&[T]` | `&v`, `.as_slice()` |
| `Option<T>` | `T` | `.unwrap()`, `.unwrap_or()`, `?` |
| `Result<T,E>` | `T` | `.unwrap()`, `?`, `match` |

## Veja Também

- [E0277: Trait Não Implementado](/erros/e0277-trait-nao-implementado/)
- [E0412: Tipo Não Encontrado](/erros/e0412-tipo-nao-encontrado/)
- [Tutorial de Tratamento de Erros](/tutoriais/tratamento-de-erros/)
- [Cheatsheet Rust](/cheatsheet/)
- [Documentação oficial: E0308](https://doc.rust-lang.org/error_codes/E0308.html)
