---
title: "Modulo std::marker em Rust: Traits de Marcacao"
url: "https://rustlang.com.br/stdlib/marker-module/"
markdown_url: "https://rustlang.com.br/stdlib/marker-module.MD"
description: "Guia completo do modulo std::marker em Rust: PhantomData, Sized, Unpin, Send, Sync, Copy e programacao em nivel de tipos com exemplos praticos."
date: "2026-02-23"
author: "Equipe Rust Brasil"
---

# Modulo std::marker em Rust: Traits de Marcacao

Guia completo do modulo std::marker em Rust: PhantomData, Sized, Unpin, Send, Sync, Copy e programacao em nivel de tipos com exemplos praticos.


## Visao Geral do Modulo std::marker

O modulo `std::marker` contem **traits de marcacao** (marker traits) — traits que nao possuem metodos, mas comunicam propriedades de tipos ao compilador. Elas sao fundamentais para o sistema de tipos do Rust e controlam aspectos como:

- Se um tipo pode ser copiado bit-a-bit (`Copy`)
- Se um tipo pode ser enviado entre threads (`Send`)
- Se um tipo pode ser compartilhado entre threads (`Sync`)
- Se o tamanho do tipo e conhecido em tempo de compilacao (`Sized`)
- Se um tipo pode ser movido de tras de um `Pin` (`Unpin`)

Alem das traits, o modulo fornece `PhantomData<T>`, um tipo de tamanho zero que permite "fingir" que uma struct usa um tipo generico sem realmente armazena-lo. Isso e essencial para programacao em nivel de tipos, controle de variancia e seguranca de FFI.

---

## Traits e Tipos Principais

### Traits de Marcacao

| Trait | Auto? | Descricao |
|---|---|---|
| `Copy` | Nao | Tipo pode ser copiado bit-a-bit (implica `Clone`) |
| `Send` | Sim | Tipo pode ser transferido entre threads |
| `Sync` | Sim | `&T` pode ser compartilhado entre threads |
| `Sized` | Sim | Tamanho conhecido em tempo de compilacao |
| `Unpin` | Sim | Tipo pode ser movido de tras de `Pin` |
| `Unsize` | — | Tipo pode ser "reduzido" (unstable) |

**"Auto"** significa que o compilador implementa a trait automaticamente quando todos os campos a satisfazem.

### PhantomData

| Tipo | Descricao |
|---|---|
| `PhantomData<T>` | Tipo de tamanho zero que "marca" que T e usado |

---

## Exemplos Praticos

### 1. Copy — Copia Implicita vs Move

```rust
// Tipos Copy: a atribuicao copia os bits, sem invalidar o original
#[derive(Debug, Clone, Copy)]
struct Ponto {
    x: f64,
    y: f64,
}

// Tipos nao-Copy: a atribuicao move o valor
#[derive(Debug, Clone)]
struct Dados {
    valores: Vec<i32>,
}

fn main() {
    // Copy: ambas as variaveis sao validas
    let p1 = Ponto { x: 1.0, y: 2.0 };
    let p2 = p1; // copia bit-a-bit
    println!("p1={p1:?}, p2={p2:?}"); // ambos validos!

    // Nao-Copy: move semantics
    let d1 = Dados { valores: vec![1, 2, 3] };
    let d2 = d1; // move! d1 nao pode mais ser usado
    // println!("{d1:?}"); // ERRO de compilacao!
    println!("d2={d2:?}");

    // Tipos primitivos sao Copy
    let a: i32 = 42;
    let b = a;
    println!("a={a}, b={b}"); // ambos validos

    // Tuplas de tipos Copy tambem sao Copy
    let t1 = (1, 2.0, true);
    let t2 = t1;
    println!("{t1:?} {t2:?}");
}
```

**Regra:** Um tipo pode ser `Copy` apenas se todos os seus campos forem `Copy` e ele nao implementar `Drop`. Tipos com alocacao heap (como `String`, `Vec`, `Box`) nunca sao `Copy`.

### 2. Send e Sync — Seguranca Entre Threads

```rust
use std::sync::{Arc, Mutex};
use std::thread;

// String e Send + Sync
// Rc<T> NAO e Send nem Sync
// Arc<T> e Send + Sync (quando T e Send + Sync)
// Mutex<T> e Send + Sync (quando T e Send)
// Cell<T> e Send mas NAO e Sync

fn demonstrar_send() {
    let dados = String::from("transferido entre threads");

    // String e Send, entao pode ser movida para outra thread
    let handle = thread::spawn(move || {
        println!("Recebi: {dados}");
    });

    handle.join().unwrap();
}

fn demonstrar_sync() {
    let dados = Arc::new(Mutex::new(vec![1, 2, 3]));

    let mut handles = vec![];

    for i in 0..3 {
        let dados = Arc::clone(&dados);
        // Arc<Mutex<Vec<i32>>> e Send + Sync,
        // entao pode ser compartilhado entre threads
        handles.push(thread::spawn(move || {
            let mut guard = dados.lock().unwrap();
            guard.push(i * 10);
        }));
    }

    for h in handles {
        h.join().unwrap();
    }

    println!("Dados finais: {:?}", dados.lock().unwrap());
}

fn main() {
    demonstrar_send();
    demonstrar_sync();
}
```

**Quando implementar manualmente Send/Sync:** Apenas quando voce tem um tipo com ponteiros raw e pode garantir a seguranca. A implementacao manual requer `unsafe`:

```rust
struct MeuBuffer {
    ptr: *mut u8,
    len: usize,
}

// SAFETY: MeuBuffer tem ownership exclusivo do ponteiro,
// entao e seguro envia-lo entre threads
unsafe impl Send for MeuBuffer {}

// SAFETY: acesso compartilhado e seguro porque
// nao ha mutacao sem sincronizacao
unsafe impl Sync for MeuBuffer {}
```

### 3. PhantomData para Seguranca de Tipos

```rust
use std::marker::PhantomData;

// Unidades de medida em nivel de tipos
struct Metros;
struct Quilometros;
struct Segundos;

struct Medida<Unidade> {
    valor: f64,
    _unidade: PhantomData<Unidade>,
}

impl<U> Medida<U> {
    fn new(valor: f64) -> Self {
        Medida {
            valor,
            _unidade: PhantomData,
        }
    }
}

// So permitimos somar medidas da mesma unidade
impl<U> std::ops::Add for Medida<U> {
    type Output = Medida<U>;

    fn add(self, other: Self) -> Self::Output {
        Medida::new(self.valor + other.valor)
    }
}

// Conversao especifica
impl Medida<Quilometros> {
    fn para_metros(self) -> Medida<Metros> {
        Medida::new(self.valor * 1000.0)
    }
}

fn calcular_velocidade(
    distancia: Medida<Metros>,
    tempo: Medida<Segundos>,
) -> f64 {
    distancia.valor / tempo.valor
}

fn main() {
    let d1 = Medida::<Metros>::new(100.0);
    let d2 = Medida::<Metros>::new(200.0);
    let total = d1 + d2; // OK: mesma unidade

    let km = Medida::<Quilometros>::new(5.0);
    let em_metros = km.para_metros();

    let tempo = Medida::<Segundos>::new(10.0);
    let vel = calcular_velocidade(total, tempo);
    println!("Velocidade: {vel} m/s");

    // ERRO de compilacao: nao pode somar metros com quilometros!
    // let errado = Medida::<Metros>::new(1.0) + Medida::<Quilometros>::new(1.0);
}
```

### 4. PhantomData para Controle de Lifetime

```rust
use std::marker::PhantomData;

struct Referencia<'a, T> {
    ptr: *const T,
    _lifetime: PhantomData<&'a T>,
}

impl<'a, T> Referencia<'a, T> {
    fn new(referencia: &'a T) -> Self {
        Referencia {
            ptr: referencia as *const T,
            _lifetime: PhantomData,
        }
    }

    fn obter(&self) -> &'a T {
        // SAFETY: o PhantomData garante que o lifetime 'a
        // e respeitado pelo borrow checker. O ponteiro e valido
        // enquanto a referencia original for valida.
        unsafe { &*self.ptr }
    }
}

fn main() {
    let valor = 42;
    let ref_wrapper = Referencia::new(&valor);
    println!("Valor: {}", ref_wrapper.obter());
}
```

### 5. Sized e ?Sized — Tipos de Tamanho Dinamico

```rust
use std::fmt::Display;

// Por padrao, parametros genericos sao Sized
fn funcao_sized<T>(val: T) -> T {
    val
}

// ?Sized permite tipos de tamanho desconhecido (como str, [T], dyn Trait)
// Mas so pode ser usado por referencia
fn imprimir<T: Display + ?Sized>(val: &T) {
    println!("{val}");
}

// Trait objects sao !Sized
fn processar(item: &dyn Display) {
    println!("Processando: {item}");
}

fn main() {
    // Tipos Sized: o tamanho e conhecido em compile-time
    let n: i32 = 42;
    funcao_sized(n);

    // Com ?Sized, podemos aceitar tanto Sized quanto !Sized
    imprimir("texto literal");           // &str (!Sized)
    imprimir(&String::from("String"));   // &String (Sized)
    imprimir(&42);                       // &i32 (Sized)

    // str e !Sized — nao pode existir como valor direto
    // let s: str = *"hello"; // ERRO!
    let s: &str = "hello"; // OK — referencia a um tipo !Sized

    // [T] e !Sized
    let slice: &[i32] = &[1, 2, 3];
    imprimir_tamanho(slice);
}

fn imprimir_tamanho<T: ?Sized>(val: &T) {
    println!("Tamanho da referencia: {} bytes", std::mem::size_of_val(&val));
    println!("Tamanho do valor: {} bytes", std::mem::size_of_val(val));
}
```

---

## Padroes Comuns

### Phantom Types para Estado em Compile-Time

Use tipos fantasma para codificar estados que sao verificados pelo compilador:

```rust
use std::marker::PhantomData;

struct Rascunho;
struct Revisado;
struct Publicado;

struct Documento<Estado> {
    titulo: String,
    conteudo: String,
    _estado: PhantomData<Estado>,
}

impl Documento<Rascunho> {
    fn new(titulo: String) -> Self {
        Documento {
            titulo,
            conteudo: String::new(),
            _estado: PhantomData,
        }
    }

    fn escrever(&mut self, texto: &str) {
        self.conteudo.push_str(texto);
    }

    fn enviar_para_revisao(self) -> Documento<Revisado> {
        Documento {
            titulo: self.titulo,
            conteudo: self.conteudo,
            _estado: PhantomData,
        }
    }
}

impl Documento<Revisado> {
    fn publicar(self) -> Documento<Publicado> {
        println!("Publicando: {}", self.titulo);
        Documento {
            titulo: self.titulo,
            conteudo: self.conteudo,
            _estado: PhantomData,
        }
    }
}

impl Documento<Publicado> {
    fn url(&self) -> String {
        format!("/artigos/{}", self.titulo.to_lowercase().replace(' ', "-"))
    }
}
```

### Opt-Out de Traits Automaticas

Para remover `Send` ou `Sync` de um tipo, use `PhantomData` com um tipo que nao as implementa:

```rust
use std::marker::PhantomData;
use std::cell::Cell;

struct NaoSync {
    dados: i32,
    _nao_sync: PhantomData<Cell<()>>, // Cell nao e Sync
}
```

---

## Quando Usar (e Quando Nao Usar)

**Use `std::marker` quando:**
- Precisar de seguranca de tipos em nivel de compilacao (phantom types)
- Trabalhar com FFI e precisar de controle de lifetime com `PhantomData`
- Implementar `Send`/`Sync` manualmente para tipos com ponteiros raw
- Precisar de `?Sized` para aceitar trait objects e slices

**Nao use `std::marker` quando:**
- Enums simples resolverem o problema de estados
- Nao estiver fazendo programacao generica avancada
- `PhantomData` tornar o codigo mais confuso sem ganho claro de seguranca
- Puder confiar nas implementacoes automaticas de `Send`/`Sync`

**Dica:** `PhantomData<T>` tem tamanho zero — nao adiciona nenhum custo em runtime. E puramente uma instrucao ao compilador.

---

## Veja Tambem

- [Send e Sync em Detalhes](/stdlib/send-sync/) — aprofundamento sobre seguranca entre threads
- [Unsafe Rust](/artigos/unsafe-rust/) — quando implementar Send/Sync manualmente
- [Modulo std::mem](/stdlib/mem-module/) — `size_of` e layout de tipos
- [Pin\<P\> em Rust](/stdlib/pin-module/) — relacao entre `Unpin` e `Pin`
- [Modulo std::any](/stdlib/any-module/) — inspecao de tipos em runtime
- [O Prelude do Rust](/stdlib/prelude/) — quais traits de marcacao sao importadas automaticamente
- [Documentacao oficial — std::marker](https://doc.rust-lang.org/std/marker/index.html)
