---
title: "AsRef, AsMut e Borrow Traits em Rust"
url: "https://rustlang.com.br/stdlib/asref-borrow/"
markdown_url: "https://rustlang.com.br/stdlib/asref-borrow.MD"
description: "Guia completo sobre AsRef, AsMut e Borrow em Rust: parâmetros genéricos, AsRef Path, Borrow para HashMap e quando usar cada um."
date: "2026-02-23"
author: "Equipe Rust Brasil"
---

# AsRef, AsMut e Borrow Traits em Rust

Guia completo sobre AsRef, AsMut e Borrow em Rust: parâmetros genéricos, AsRef Path, Borrow para HashMap e quando usar cada um.


## O que são AsRef, AsMut e Borrow?

Esses três traits lidam com **conversão de referências** — transformar uma referência de um tipo em uma referência de outro tipo, sem cópia. Embora pareçam similares, cada um tem um propósito distinto:

- **`AsRef<T>`**: "posso ser visto como uma referência a `T`". Usado para tornar funções genéricas que aceitam diferentes tipos de entrada. Exemplo clássico: aceitar tanto `String` quanto `&str`, ou tanto `PathBuf` quanto `&Path`.

- **`AsMut<T>`**: versão mutável de `AsRef`. "Posso ser visto como uma referência mutável a `T`".

- **`Borrow<T>`**: similar a `AsRef`, mas com um **contrato adicional**: o tipo emprestado deve ter o mesmo comportamento de `Hash`, `Eq` e `Ord` que o tipo original. Essencial para chaves de `HashMap` e `HashSet`.

A regra prática: use **`AsRef`** para funções genéricas comuns, use **`Borrow`** para containers que dependem de hash e igualdade.

---

## Definição dos Traits

```rust
// std::convert::AsRef
pub trait AsRef<T: ?Sized> {
    fn as_ref(&self) -> &T;
}

// std::convert::AsMut
pub trait AsMut<T: ?Sized> {
    fn as_mut(&mut self) -> &mut T;
}

// std::borrow::Borrow
pub trait Borrow<Borrowed: ?Sized> {
    fn borrow(&self) -> &Borrowed;
}
```

### Diferenças-chave

| Aspecto | AsRef | Borrow |
|---------|-------|--------|
| Propósito | Conversão genérica de referência | Empréstimo com contrato de equivalência |
| Contrato Hash/Eq | Nenhum | Obrigatório: hash e eq devem ser consistentes |
| Uso principal | Parâmetros de função | Chaves de HashMap/HashSet |
| Implementação blanket | `T: AsRef<T>` para todo `T` | `T: Borrow<T>` para todo `T` |

---

## Como Implementar

### AsRef manual

```rust
struct CaminhoConfig {
    base: String,
    arquivo: String,
}

impl AsRef<str> for CaminhoConfig {
    fn as_ref(&self) -> &str {
        &self.arquivo
    }
}

impl AsRef<std::path::Path> for CaminhoConfig {
    fn as_ref(&self) -> &std::path::Path {
        std::path::Path::new(&self.arquivo)
    }
}

fn imprimir_caminho(caminho: impl AsRef<std::path::Path>) {
    println!("Caminho: {}", caminho.as_ref().display());
}

fn main() {
    let config = CaminhoConfig {
        base: String::from("/etc"),
        arquivo: String::from("/etc/app/config.toml"),
    };

    imprimir_caminho(&config);
    imprimir_caminho("/usr/local/bin");
    imprimir_caminho(String::from("/home/user"));
}
```

### Borrow manual

```rust
use std::borrow::Borrow;
use std::hash::{Hash, Hasher};

#[derive(Debug)]
struct EmailNormalizado {
    original: String,
    normalizado: String,
}

impl EmailNormalizado {
    fn novo(email: &str) -> Self {
        EmailNormalizado {
            original: email.to_string(),
            normalizado: email.to_lowercase(),
        }
    }
}

// Hash usa o valor normalizado
impl Hash for EmailNormalizado {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.normalizado.hash(state);
    }
}

// Eq usa o valor normalizado
impl PartialEq for EmailNormalizado {
    fn eq(&self, other: &Self) -> bool {
        self.normalizado == other.normalizado
    }
}

impl Eq for EmailNormalizado {}

// Borrow<str> permite buscar no HashMap com &str
impl Borrow<str> for EmailNormalizado {
    fn borrow(&self) -> &str {
        &self.normalizado
    }
}

fn main() {
    use std::collections::HashSet;

    let mut emails = HashSet::new();
    emails.insert(EmailNormalizado::novo("Ana@Exemplo.COM"));
    emails.insert(EmailNormalizado::novo("bruno@exemplo.com"));

    // Busca com &str (graças a Borrow<str>)
    // Precisamos buscar com o valor normalizado
    println!("Contém ana@exemplo.com? {}", emails.contains("ana@exemplo.com"));
    println!("Contém bruno@exemplo.com? {}", emails.contains("bruno@exemplo.com"));
}
```

---

## Exemplos Práticos

### Exemplo 1: AsRef<str> para APIs flexíveis

```rust
fn contar_palavras(texto: impl AsRef<str>) -> usize {
    texto.as_ref().split_whitespace().count()
}

fn contem_palavra(texto: impl AsRef<str>, palavra: impl AsRef<str>) -> bool {
    let texto = texto.as_ref().to_lowercase();
    let palavra = palavra.as_ref().to_lowercase();
    texto.contains(&palavra)
}

fn main() {
    // Funciona com &str
    println!("{}", contar_palavras("Rust é incrível")); // 3

    // Funciona com String
    let frase = String::from("A linguagem Rust é segura e rápida");
    println!("{}", contar_palavras(&frase)); // 7
    println!("{}", contar_palavras(frase.clone())); // 7

    // Funciona com diferentes combinações
    println!("{}", contem_palavra("Rust é incrível", "RUST")); // true
    println!("{}", contem_palavra(frase, String::from("segura"))); // true
}
```

### Exemplo 2: AsRef<Path> para operações de arquivo

```rust
use std::path::Path;
use std::fs;

fn arquivo_existe(caminho: impl AsRef<Path>) -> bool {
    caminho.as_ref().exists()
}

fn extensao(caminho: impl AsRef<Path>) -> Option<String> {
    caminho
        .as_ref()
        .extension()
        .and_then(|ext| ext.to_str())
        .map(|s| s.to_string())
}

fn listar_info(caminho: impl AsRef<Path>) {
    let p = caminho.as_ref();
    println!("Caminho: {}", p.display());
    println!("Existe: {}", p.exists());
    println!("É arquivo: {}", p.is_file());
    println!("Extensão: {:?}", extensao(p));
}

fn main() {
    // Aceita &str
    println!("Existe? {}", arquivo_existe("/etc/hosts"));

    // Aceita String
    let caminho = String::from("/tmp/teste.txt");
    listar_info(&caminho);

    // Aceita &Path
    let path = Path::new("/usr/bin/rustc");
    listar_info(path);

    // Aceita PathBuf
    let pathbuf = std::path::PathBuf::from("/home");
    listar_info(&pathbuf);
}
```

### Exemplo 3: Borrow em HashMap

```rust
use std::collections::HashMap;
use std::borrow::Borrow;

fn main() {
    let mut capitais: HashMap<String, String> = HashMap::new();

    capitais.insert(
        String::from("Brasil"),
        String::from("Brasília"),
    );
    capitais.insert(
        String::from("Argentina"),
        String::from("Buenos Aires"),
    );
    capitais.insert(
        String::from("Chile"),
        String::from("Santiago"),
    );

    // HashMap::get aceita qualquer tipo que implemente Borrow<str>
    // String implementa Borrow<str>, então podemos buscar com &str
    if let Some(capital) = capitais.get("Brasil") {
        println!("Capital do Brasil: {}", capital);
    }

    // Também funciona com String
    let pais = String::from("Argentina");
    if let Some(capital) = capitais.get(&pais) {
        println!("Capital da Argentina: {}", capital);
    }

    // contains_key também usa Borrow
    println!("Tem Chile? {}", capitais.contains_key("Chile"));

    // remove também usa Borrow
    capitais.remove("Chile");
    println!("Após remover Chile: {:?}", capitais.keys().collect::<Vec<_>>());
}
```

### Exemplo 4: AsMut para buffers

```rust
fn preencher_zeros(buffer: &mut impl AsMut<[u8]>) {
    let slice = buffer.as_mut();
    for byte in slice.iter_mut() {
        *byte = 0;
    }
}

fn capitalizar_ascii(texto: &mut impl AsMut<[u8]>) {
    let bytes = texto.as_mut();
    if let Some(primeiro) = bytes.first_mut() {
        if primeiro.is_ascii_lowercase() {
            *primeiro = primeiro.to_ascii_uppercase();
        }
    }
}

fn main() {
    // Com Vec<u8>
    let mut buffer = vec![1u8, 2, 3, 4, 5];
    preencher_zeros(&mut buffer);
    println!("{:?}", buffer); // [0, 0, 0, 0, 0]

    // Com array
    let mut arr = [10u8, 20, 30];
    preencher_zeros(&mut arr);
    println!("{:?}", arr); // [0, 0, 0]

    // Com Vec<u8> como texto
    let mut texto = b"rust".to_vec();
    capitalizar_ascii(&mut texto);
    println!("{}", String::from_utf8_lossy(&texto)); // Rust
}
```

### Exemplo 5: Quando usar AsRef vs Borrow vs Deref

```rust
use std::borrow::Borrow;
use std::path::Path;

// AsRef: para conversões genéricas em parâmetros de função
fn processar_texto(input: impl AsRef<str>) {
    let s: &str = input.as_ref();
    println!("Processando: '{}'", s);
}

// Borrow: para containers que dependem de Hash/Eq
fn buscar_em_mapa<K, V>(mapa: &std::collections::HashMap<K, V>, chave: &str) -> Option<&V>
where
    K: std::hash::Hash + Eq + Borrow<str>,
{
    mapa.get(chave)
}

// Deref: acontece automaticamente via coercion
fn tamanho(s: &str) -> usize {
    s.len()
}

fn main() {
    let string = String::from("exemplo");

    // AsRef: chamada explícita com as_ref()
    processar_texto(&string);
    processar_texto("literal");

    // Borrow: usado internamente por HashMap
    let mut mapa = std::collections::HashMap::new();
    mapa.insert(String::from("chave"), 42);
    println!("{:?}", buscar_em_mapa(&mapa, "chave"));

    // Deref: coerção automática &String → &str
    println!("Tamanho: {}", tamanho(&string));
}
```

---

## Quando Usar Cada Um?

### Use `AsRef<T>` quando:
- Sua função precisa de uma referência a `T` e você quer aceitar vários tipos de entrada
- Não há requisito de consistência entre Hash/Eq
- Cenário típico: `AsRef<str>`, `AsRef<Path>`, `AsRef<[u8]>`

### Use `Borrow<T>` quando:
- Você está implementando um container ou coleção
- A busca/comparação precisa ser consistente com Hash e Eq
- Cenário típico: chaves de `HashMap`, elementos de `HashSet`

### Use `Deref` quando:
- Você está criando um smart pointer ou tipo wrapper
- Quer que todos os métodos do tipo interno estejam disponíveis
- Cenário típico: `Box<T>`, `Rc<T>`, `Arc<T>`, newtypes

---

## Padrões e Boas Práticas

1. **Prefira `AsRef<str>` a `&String`**: Funções que aceitam `impl AsRef<str>` são mais genéricas e idiomáticas que funções com `&String`.

2. **O contrato de Borrow é sério**: Se `a.borrow() == b.borrow()`, então `hash(a) == hash(b)` **deve** ser verdadeiro. Violar isso quebra HashMap/HashSet.

3. **AsRef é transitivo na stdlib**: `String: AsRef<str>`, `str: AsRef<Path>`, mas `String` **não** implementa `AsRef<Path>` diretamente — use conversão explícita quando necessário.

4. **Não implemente AsRef e Deref para o mesmo Target**: Isso pode causar ambiguidade. Escolha um: `Deref` para smart pointers, `AsRef` para conversões genéricas.

5. **`impl AsRef<str>` vs `&str`**: Para funções simples, `&str` é mais direto e legível. Use `impl AsRef<str>` apenas quando realmente precisa aceitar múltiplos tipos.

6. **Borrow em APIs de coleção**: Se você está criando uma coleção que faz lookup por chave, use `Borrow` no método de busca, como a stdlib faz com `HashMap::get`.

---

## Veja Também

- [Deref e DerefMut](/stdlib/deref/) — smart pointers e deref coercion
- [From e Into](/stdlib/from-into/) — conversões de valor (não referência)
- [Hash Trait](/stdlib/hash-trait/) — o contrato Hash+Eq que Borrow respeita
- [HashMap](/stdlib/hashmap/) — usa Borrow para busca flexível de chaves
