---
title: "E0038: Trait Não Pode Ser Trait Object no Rust"
url: "https://rustlang.com.br/erros/e0038-trait-object-unsafe/"
markdown_url: "https://rustlang.com.br/erros/e0038-trait-object-unsafe.MD"
description: "Como resolver o erro E0038 do Rust: o trait não pode ser usado como trait object. Entenda as regras de object safety e alternativas como enum dispatch e genéricos."
date: "2026-02-23"
author: "Equipe Rust Brasil"
---

# E0038: Trait Não Pode Ser Trait Object no Rust

Como resolver o erro E0038 do Rust: o trait não pode ser usado como trait object. Entenda as regras de object safety e alternativas como enum dispatch e genéricos.


# E0038: Trait Não Pode Ser Trait Object

O erro **E0038** ocorre quando você tenta usar um trait como **trait object** (`dyn Trait`) mas o trait não satisfaz as regras de **object safety** (segurança de objeto). Nem todo trait pode ser usado com `dyn` — há restrições específicas.

## A Mensagem de Erro

```
error[E0038]: the trait `Clonavel` cannot be made into an object
 --> src/main.rs:8:19
  |
8 |     let item: Box<dyn Clonavel> = Box::new(texto);
  |                   ^^^^^^^^^^^^ `Clonavel` cannot be made into an object
  |
note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
  = note: the trait cannot be made into an object because it requires `Self: Sized`
```

## O Que Significa

Um **trait object** (`dyn Trait`) permite polimorfismo em tempo de execução — diferentes tipos que implementam o mesmo trait podem ser tratados uniformemente. Internamente, o Rust usa uma **vtable** (tabela de funções virtuais) para despachar as chamadas de método.

Para que isso funcione, o compilador precisa saber:
1. O **tamanho** de cada chamada de método (não pode depender de `Self`)
2. Qual **método** chamar (precisa ser resolvível pela vtable)

As regras de object safety exigem que o trait:

- **Não tenha métodos que retornem `Self`** (o tipo concreto é desconhecido em runtime)
- **Não tenha parâmetros genéricos de tipo em métodos**
- **Não exija `Self: Sized`** (trait objects são `!Sized`)
- **Não tenha funções associadas sem `self`** (não podem estar na vtable)

## Código com Erro

### Método que retorna Self

```rust
trait Clonavel {
    fn clonar(&self) -> Self;  // Retorna Self — não é object safe
}

fn processar(item: &dyn Clonavel) {  // ERRO
    let copia = item.clonar();
}
```

### Método com parâmetro genérico

```rust
trait Conversor {
    fn converter<T>(&self) -> T;  // Genérico — não é object safe
}

fn processar(item: &dyn Conversor) {  // ERRO
    let valor: i32 = item.converter();
}
```

### Trait com Self: Sized

```rust
trait Fabrica: Sized {  // Requer Sized — não é object safe
    fn criar() -> Self;
}

fn processar(item: &dyn Fabrica) {  // ERRO
}
```

## Como Resolver

### Solução 1: Usar `where Self: Sized` para Excluir Métodos

Marque os métodos problemáticos para que não entrem na vtable:

```rust
trait Clonavel {
    fn nome(&self) -> &str;

    // Este método não estará disponível via dyn Trait
    fn clonar(&self) -> Self where Self: Sized;
}

struct Texto {
    conteudo: String,
}

impl Clonavel for Texto {
    fn nome(&self) -> &str {
        &self.conteudo
    }

    fn clonar(&self) -> Self {
        Texto { conteudo: self.conteudo.clone() }
    }
}

fn processar(item: &dyn Clonavel) {
    // Pode usar `nome()`, mas não `clonar()`
    println!("Nome: {}", item.nome());
}
```

### Solução 2: Retornar Box em Vez de Self

Em vez de retornar `Self`, retorne `Box<dyn Trait>`:

```rust
trait Animal {
    fn nome(&self) -> &str;
    fn filhote(&self) -> Box<dyn Animal>;  // Box em vez de Self
}

struct Gato {
    nome_gato: String,
}

impl Animal for Gato {
    fn nome(&self) -> &str {
        &self.nome_gato
    }

    fn filhote(&self) -> Box<dyn Animal> {
        Box::new(Gato {
            nome_gato: format!("Filhote de {}", self.nome_gato),
        })
    }
}

fn processar(animal: &dyn Animal) {
    let filho = animal.filhote();
    println!("Filhote: {}", filho.nome());
}
```

### Solução 3: Usar Genéricos em Vez de Trait Objects

Se possível, use **dispatch estático** com genéricos em vez de `dyn`:

```rust
trait Conversor {
    fn para_string(&self) -> String;
}

// Em vez de `dyn Conversor`, use genérico:
fn processar<T: Conversor>(item: &T) {
    println!("{}", item.para_string());
}

// Ou com `impl Trait`:
fn processar_v2(item: &impl Conversor) {
    println!("{}", item.para_string());
}
```

Genéricos têm dispatch estático (resolvido em compilação) e geralmente são mais rápidos que trait objects, mas geram código duplicado para cada tipo concreto.

### Solução 4: Usar Enum Dispatch

Se você tem um conjunto finito e conhecido de tipos, use um enum:

```rust
enum Forma {
    Circulo { raio: f64 },
    Retangulo { largura: f64, altura: f64 },
    Triangulo { base: f64, altura: f64 },
}

impl Forma {
    fn area(&self) -> f64 {
        match self {
            Forma::Circulo { raio } => std::f64::consts::PI * raio * raio,
            Forma::Retangulo { largura, altura } => largura * altura,
            Forma::Triangulo { base, altura } => base * altura / 2.0,
        }
    }

    fn nome(&self) -> &str {
        match self {
            Forma::Circulo { .. } => "Círculo",
            Forma::Retangulo { .. } => "Retângulo",
            Forma::Triangulo { .. } => "Triângulo",
        }
    }
}

fn main() {
    let formas: Vec<Forma> = vec![
        Forma::Circulo { raio: 5.0 },
        Forma::Retangulo { largura: 3.0, altura: 4.0 },
    ];

    for f in &formas {
        println!("{}: {:.2}", f.nome(), f.area());
    }
}
```

Enum dispatch é mais rápido que trait objects (sem indireção de ponteiro) e permite métodos que retornam `Self`.

## Regras de Object Safety Resumidas

| Regra | Object Safe? |
|---|---|
| Método com `&self` / `&mut self` | Sim |
| Método que retorna `Self` | Nao |
| Método com genéricos de tipo | Nao |
| Trait com `Self: Sized` | Nao |
| Função associada sem `self` | Nao |
| Método com `where Self: Sized` | Sim (excluído da vtable) |

## Veja Também

- [E0277: Trait Não Implementado](/erros/e0277-trait-nao-implementado/)
- [E0046: Items Faltando na Implementação](/erros/e0046-items-faltando-impl/)
- [E0107: Argumentos Genéricos Incorretos](/erros/e0107-argumentos-genericos-errados/)
- [Glossário Rust](/glossario/)
- [Documentação oficial: E0038](https://doc.rust-lang.org/error_codes/E0038.html)
