Rust: Referências e empréstimos no Rust

Última atualização: 2026-08-26

Uma citação é como um cartão de biblioteca — você pode pegá-la emprestada (citação somente para leitura) ou solicitar permissão exclusiva para reescrevê-la (citação editável), mas não pode fazer as duas coisas ao mesmo tempo.

O mecanismo de referência do Rust permite acessar dados sem transferir a propriedade. Isso é chamado de “empréstimo”.


1. O que você vai aprender


2. Diagramas conceituais

100%
flowchart LR
    subgraph "Transfer of Ownership"
        A1["Data String"] -->|"let s2 = s1<br>move"| B1["New Owner s2"]
        B1 -->|"s1 Failure"| C1["Compilation Error<br>println!(s1)"]
    end
    subgraph "Citation, Borrowing"
        A2["Data String"] -->|"let r = &s<br>borrow"| B2["Quote r"]
        B2 -->|"r Return after use<br>s Still valid"| C2["✅ Secure Access"]
    end

3. A história de uma biblioteca

(1) Desgosto: O livro foi rasgado em pedaços

Há um livro popular intitulado Programação em Rust na biblioteca do Tom, e ele só pode ser emprestado uma vez:

“Se ao menos eu pudesse deixar várias pessoas lerem o mesmo livro ao mesmo tempo sem que elas o destruíssem...”

(2) Soluções para referências em Rust

RUST
fn main() {
    let book = String::from("Rust Programming");

    // Multiple immutable references: Multiple people at the same time "read-only" check out
    let reader1 = &book;   // Reader 1 checks out (read-only)
    let reader2 = &book;   // Reader 2 checks out (read-only)
    println!("Readers 1 See: {}", reader1);
    println!("Readers 2 See: {}", reader2);
    // Both references are valid at the same time -- because everyone has read-only access

    let mut notebook = String::from("Notebook");

    // Mutable References: write-only permission
    let writer = &mut notebook;  // Only one person can make changes
    writer.push_str("-- I wrote some notes");
    println!("Rewriter: {}", writer);
    // writer ends scope here, only then can others borrow it again.
}

As regras de citação são como as regras de uma biblioteca: Ou várias pessoas podem ler ao mesmo tempo (múltiplo &T), ou uma pessoa pode editar sozinha (um &mut T) — mas isso não pode acontecer simultaneamente.


4. Regras para empréstimos

100%
graph TB
    A[Borrowing Rules] --> B[You can only choose one of them.]
    B --> C[Multiple immutable references &T]
    B --> D[Or a mutable reference &mut T]
    B --> E[Cannot coexist]
    A --> F[References must always be valid.]
    F --> G[There must be no dangling references.]
Regra Descrição Consequências da violação
Várias referências &T ou uma única referência &mut T Referências imutáveis e mutáveis não podem coexistir Erro de compilação
As referências devem ser válidas Uma referência não pode permanecer ativa após o objeto ao qual se refere ter sido destruído Erro de compilação
Quando uma referência é imutável, o valor original também não pode ser modificado Quando &T existe, o valor original não pode ser modificado por meio de &mut T Erro de compilação
Âmbito da NLL O âmbito de &mut T termina após seu último uso Otimização orientada pelo compilador

(2) Comparação entre tipos de referência

Tipo de citação Sintaxe Permissões Número máximo permitido Usos típicos
Referência imutável &T Somente leitura Múltipla Acesso somente leitura aos parâmetros da função
Referência da variável &mut T Leitura/gravação 1 O parâmetro da função modifica os dados
Ponteiro de fat (fatia) &[T] Somente leitura Múltiplo Fatia de array/string

(3) Referência rápida para cenários de empréstimo

Cenário Abordagem recomendada Exemplo
Acesso à função somente leitura &T fn len(s: &String) -> usize
Funções que modificam dados &mut T fn push(s: &mut String, ch: char)
Uso de dados da função T (passagem por valor) fn consume(s: String)
Dados de retorno da função T (Valor de retorno) fn create() -> String
Várias funções compartilham acesso somente leitura &T Várias funções recebem o mesmo &T
Modificações alternadas &mut T (Multiplexação por divisão de tempo) O NLL permite a criação alternada de &mut T

5. Exemplos de citações

▶ Exemplo 1: Referências imutáveis — Acesso somente para leitura (Dificuldade ⭐⭐)

RUST
// ============================================
// Immutable References &T: Multiple readers can borrow items at the same time
// ============================================

fn calculate_length(s: &String) -> usize {
    // s is a String reference, no ownership
    s.len()
}  // s goes out of scope, but since it's a reference, it will not destroy the String

fn main() {
    let s = String::from("Hello, Rust!");

    let len = calculate_length(&s);  // Borrow s, no transfer of ownership
    println!("'{}' The length of is: {}", s, len);  // ✅ s Still available

    // Multiple immutable references can coexist
    let r1 = &s;
    let r2 = &s;
    println!("r1: {}, r2: {}", r1, r2);  // ✅ Read simultaneously
}

Resultado:

TEXT 📖 Somente leitura
'Hello, Rust!' The length of is: 12
r1: Hello, Rust!, r2: Hello, Rust!

&s cria uma referência a s; quando passada para uma função, a propriedade não é transferida. Após o retorno da função, a referência se torna inválida, mas s ainda existe. Isso é o que se conhece como “empréstimo” — você usa e depois devolve.


▶ Exemplo 2: Referências mutáveis — Permissões exclusivas de modificação (Dificuldade ⭐⭐)

RUST
// ============================================
// Mutable References &mut T: Only one writer at a time
// ============================================

fn main() {
    let mut s = String::from("Hello");

    // Create a mutable reference
    let r = &mut s;
    r.push_str(", world!");
    println!("Modifying Through a Variable Reference: {}", r);
    // r is used here for the last time, NLL ends

    // After the mutable reference ends, you can create a new mutable reference.
    let r2 = &mut s;
    r2.push_str("!!");
    println!("Another mutable reference: {}", r2);

    // --- Examples of Errors (Uncomment to view compilation errors) ---
    // let mut s2 = String::from("test");
    // let ref1 = &mut s2;
    // let ref2 = &mut s2;  // ❌ There cannot be two mutable references at the same time.
    // println!("{}, {}", ref1, ref2);
}

Resultado:

TEXT 📖 Somente leitura
Modifying Through a Variable Reference: Hello, world!
Another mutable reference: Hello, world!!!

&mut é mutável — o valor da referência pode ser modificado. No entanto, o Rust impõe a regra de que apenas uma referência mutável pode existir por vez. Isso evita corridas de dados — não são necessários bloqueios nem operações atômicas; a questão é resolvida inteiramente em tempo de compilação.


▶ Exemplo 3: Referências imutáveis e mutáveis não podem coexistir (Dificuldade ⭐⭐⭐)

RUST
// ============================================
// Demonstration of Conflicts Between Immutable and Mutable References
// ============================================

fn main() {
    let mut data = String::from("Key Data");

    let r1 = &data;       // ✅ Immutable References 1
    let r2 = &data;       // ✅ Immutable References 2
    println!("r1: {}, r2: {}", r1, r2);
    // r1 and r2 are used here for the last time

    let r3 = &mut data;   // ✅ At this point, you can create a mutable reference.
    r3.push_str("--Modified");
    println!("r3: {}", r3);

    // --- Examples of Errors: A mutable reference cannot be created while an immutable reference still exists. ---
    // let mut s = String::from("Demo");
    // let r_a = &s;        // Immutable References
    // let r_b = &mut s;    // ❌ Compilation Error: immutable reference already exists
    // println!("{}, {}", r_a, r_b);
}

Resultado:

TEXT 📖 Somente leitura
r1: Key Data, r2: Key Data
r3: Key Data--Modified

Ponto-chave: As referências imutáveis r1 e r2 saem do escopo após seu último uso (println!), e só então a referência mutável r3 pode ser criada. Isso é o NLL (Non-Lexical Lifetime) — o compilador determina de forma inteligente quando uma referência não está mais em uso, em vez de esperar pelo fim do bloco.


▶ Exemplo 4: Como evitar referências pendentes (Dificuldade ⭐⭐⭐)

RUST
// ============================================
// How Do Compilers Prevent Dangling References?
// ============================================

// Examples of Errors: Return a reference to a local variable
// fn dangle() -> &String {
//     let s = String::from("hello");
//     &s  // ❌ Compilation Error: s is destroyed at the end of the function, the reference would be dangling
// }

// The Correct Approach: Return String directly (transfer of ownership)
fn no_dangle() -> String {
    let s = String::from("hello");
    s  // Return String directly, ownership is transferred to the caller
}

fn main() {
    let s = no_dangle();
    println!("Safe Return Values: {}", s);

    // The Correct Way to Reference Local Variables: Use within the scope
    let local = String::from("Local Data");
    let r = &local;          // Quote
    println!("Referencing Local Variables: {}", r);
    // r ends here, local is still valid
}  // local is destroyed here (later than r), safe

Resultado:

TEXT 📖 Somente leitura
Safe Return Values: hello
Referencing Local Variables: Local Data

Uma referência pendente ocorre quando a memória apontada por uma referência foi desalocada. O compilador do Rust consegue detectar essa situação em tempo de compilação — se o objeto apontado por uma referência for destruído após a criação da referência, o compilador reportará um erro. Isso elimina completamente bugs como os “ponteiros pendentes”.


▶ Exemplo 5: Exercício abrangente — Operações com contas bancárias (Dificuldade ⭐⭐⭐)

RUST
// ============================================
// Comprehensive Example: Applications of References in Real-Life Scenarios
// ============================================

struct Account {
    owner: String,
    balance: f64,
}

fn check_balance(account: &Account) -> String {
    format!("{} balance: {:.2} yuan", account.owner, account.balance)
}

fn deposit(account: &mut Account, amount: f64) {
    if amount <= 0.0 {
        println!("The deposit amount must be greater than 0");
        return;
    }
    account.balance += amount;
    println!("Deposit {:.2} Yuan Chenggong", amount);
}

fn transfer(from: &mut Account, to: &mut Account, amount: f64) -> bool {
    if amount <= 0.0 || from.balance < amount {
        println!("Transfer Failed: Insufficient balance or invalid amount");
        return false;
    }
    from.balance -= amount;
    to.balance += amount;
    println!("Transfer {:.2} yuan: {} -> {}", amount, from.owner, to.owner);
    true
}

fn show_accounts(accounts: &[Account]) {
    println!("--- Account List ---");
    for (i, acc) in accounts.iter().enumerate() {
        println!("{}. {} balance: {:.2} yuan", i + 1, acc.owner, acc.balance);
    }
}

fn main() {
    let mut alice = Account { owner: String::from("Alice"), balance: 1000.0 };
    let mut bob = Account { owner: String::from("Bob"), balance: 500.0 };

    println!("{}", check_balance(&alice));
    println!("{}", check_balance(&bob));

    deposit(&mut alice, 200.0);
    println!("{}", check_balance(&alice));

    transfer(&mut alice, &mut bob, 300.0)?;

    let accounts = [&alice, &bob];
    show_accounts(&accounts);

    let total: f64 = accounts.iter().map(|a| a.balance).sum();
    println!("Total Deposits: {:.2} yuan", total);
}

Resultado:

TEXT 📖 Somente leitura
Alice balance: 1000.00 yuan
Bob balance: 500.00 yuan
Deposit 200.00 Yuan Successful
Alice balance: 1200.00 yuan
Transfer 300.00 yuan: Alice -> Bob
--- Account List ---
1. Alice balance: 900.00 yuan
2. Bob balance: 800.00 yuan
Total Deposits: 1700.00 yuan

Este exemplo demonstra a aplicação prática dos três tipos de referência: &T (consulta somente leitura), &mut T (operação de modificação) e &[T] (percorro somente leitura). transfer requer duas referências &mut T simultaneamente, o que é seguro em Rust, pois elas apontam para dados diferentes.


❓ Perguntas Frequentes

P: Qual é a diferença entre uma referência e um ponteiro? R: Uma referência é um ponteiro cuja validade é garantida. As referências nunca são nulas e sempre apontam para uma memória válida. Em C, um int* pode ser NULL ou “dangling”, mas em Rust, um &i32 tem validade garantida.

P: &T e &mut T podem coexistir? R: Não. Esse é um princípio fundamental das regras de empréstimo do Rust. É possível ter várias referências somente para leitura (&T) ou uma única referência para leitura e gravação (&mut T), mas não ambas ao mesmo tempo. Isso garante que não ocorram problemas relacionados à “leitura de dados alterados”.

P: O que é NLL (Non-Lexical Lifetime)? R: O NLL permite que as referências expirem após seu último uso, em vez de esperar até o final do bloco. Isso reduz significativamente a rigidez do código. Por exemplo, após let r = &mut x; r.push(1);, r expira, e você pode criar imediatamente uma nova referência mutável.

P: Quando se deve usar uma referência em vez de passar por propriedade? R: Use uma referência quando precisar apenas “dar uma olhada” nos dados, e use a propriedade quando precisar “possuir” ou “manter” os dados a longo prazo. Use referências para parâmetros de função sempre que possível; dessa forma, quem chama a função não precisa se preocupar com a perda da propriedade.

P: É possível armazenar uma referência em uma estrutura? R: Sim, mas é preciso especificar um parâmetro de tempo de vida. Isso está na Lição 11. Em termos simples, quando uma estrutura contém uma referência, é preciso informar ao compilador “por quanto tempo essa referência permanecerá ativa”.


📖 Resumo


📝 Exercícios

  1. Dificuldade ⭐: Escreva uma função fn print_message(msg: &String) que exiba a string que lhe for passada. Em main, crie String e, em seguida, chame essa função para verificar se a variável original continua acessível após a chamada.
  2. Dificuldade ⭐⭐: Escreva um programa para criar um mut String. Primeiro, crie duas referências imutáveis e exiba-as; em seguida, crie uma referência mutável, modifique seu conteúdo e exiba o resultado modificado.
  3. Dificuldade ⭐⭐⭐: Tente escrever uma função que retorne uma referência (como fn get_ref() -> &String) e observe as mensagens de erro do compilador. Em seguida, modifique-a para que retorne a propriedade de String e entenda por que o Rust proíbe o retorno de referências a variáveis locais.
Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%