💻 Exemplos: Capítulo 07: Lifetimes e Segurança de Referências

Especialização em Sistemas com Rust • Demonstrações Práticas Compiláveis


🎯 Objetivo dos Exemplos

Apresentar a sintaxe e o propósito dos parâmetros genéricos de tempo de vida (Lifetimes 'a), explicando como o compilador do Rust assegura que nenhuma referência possa apontar para dados já desalocados da memória, eliminando por completo o temido erro de Dangling Pointer.


1. Código Fonte Completo (src/main.rs)

//! Demonstração Prática de Lifetimes Explícitos e o Lifetime Especial 'static

/// Retorna a fatia de string com maior comprimento.
/// O parâmetro genérico <'a> informa ao compilador que a referência retornada
/// viverá pelo menos o tempo mínimo em que tanto 'x' quanto 'y' forem válidos.
fn selecionar_string_mais_longa<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

/// Estrutura que armazena uma referência em vez de ser dona do dado (Zero Copy).
/// O lifetime 'a garante que uma instância de 'ExtratoComando' não pode
/// viver mais tempo do que a string original à qual 'comando' faz referência.
struct ExtratoComando<'a> {
    comando: &'a str,
    severidade: u8,
}

impl<'a> ExtratoComando<'a> {
    fn exibir_relatorio(&self) {
        println!("  [Severidade {}] Comando analisado: '{}'", self.severidade, self.comando);
    }
}

fn main() {
    println!("=== SEGURANÇA DETERMINÍSTICA DE LIFETIMES ===");

    // 1. Uso de Função com Lifetimes Anotados
    let string1 = String::from("SISTEMA_OPERACIONAL_RUST");
    let resultado;
    {
        let string2 = String::from("KERNEL_CORE");
        // string1 e string2 estão vivas neste escopo interno
        resultado = selecionar_string_mais_longa(string1.as_str(), string2.as_str());
        println!("Mais longa selecionada no escopo interno: '{}'", resultado);
    }
    // 'string1' ainda vive aqui, mas se 'resultado' dependesse de 'string2'
    // e fosse lido fora do escopo de string2, o rustc emitiria erro de compilação!

    // 2. Struct com Campos de Referência (Zero Copy)
    let payload_rede = String::from("POST /api/v1/auth HTTP/1.1");
    let extrato = ExtratoComando {
        comando: &payload_rede[0..17], // Slice referenciando o buffer original
        severidade: 1,
    };
    extrato.exibir_relatorio();

    // 3. O Lifetime 'static
    // Strings literais possuem o lifetime 'static: vivem durante toda a execução
    // do programa porque são compiladas diretamente no segmento de dados do binário (ELF/PE).
    let constante_sistema: &'static str = "RUST_BARE_METAL_SECURE_BUILD";
    println!("\nConstante estática do binário com lifetime 'static: {}", constante_sistema);

    // 4. Lifetimes e Elisão Automática
    // Em funções com apenas uma referência de entrada, o compilador elide os lifetimes:
    let primeira_palavra = obter_primeira_palavra(&payload_rede);
    println!("Primeiro verbo HTTP extraído via elisão de lifetimes: '{}'", primeira_palavra);
}

// O compilador aplica a regra de elisão: fn obter_primeira_palavra<'a>(s: &'a str) -> &'a str
fn obter_primeira_palavra(s: &str) -> &str {
    let bytes = s.as_bytes();
    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }
    &s[..]
}

2. Saída Esperada no Terminal

=== SEGURANÇA DETERMINÍSTICA DE LIFETIMES ===
Mais longa selecionada no escopo interno: 'SISTEMA_OPERACIONAL_RUST'
  [Severidade 1] Comando analisado: 'POST /api/v1/auth'

Constante estática do binário com lifetime 'static: RUST_BARE_METAL_SECURE_BUILD
Primeiro verbo HTTP extraído via elisão de lifetimes: 'POST'